JDK 中的Observer设计模式

来源:互联网 发布:一级消防工程师软件 编辑:程序博客网 时间:2024/05/22 11:33

1.Observer设计模式概要

   Observer设计模式在GOF里属于行为设计模式。JDK里提供的observer设计模式的实现由java.util.Observable类和java.util.Observer接口组成。从名字上可以清楚的看出两者在

Observer设计模式中分别扮演的角色:Observer是观察者角色,Observable是被观察目标(subject)角色。

   Observable是一个封装subject基本功能的类,比如注册observer(attach功能),注销observer(detatch功能)等。这些功能是任何一个扮演observerable角色的类都需要实现的,

从这一点上来讲,JDK里将这些通用功能专门封装在一个类里,显得合情合理。通常情况下,我们的类只要从Observerable类派生就可以称为observerable角色类,使用非常简单。

2.使用observer设计模式存在的困难

  但我们不得不注意到,在项目实际开发当中,情况往往要复杂得多。java不支持多继承特性在很多时候是阻碍我们使用observer设计模式的绊脚石。比如说,我们设计的一个类已经是某

个类的派生类,在这种情况下同时想让它扮演observerable角色将变得麻烦。如何实现“多继承”的效果是摆在我们面前的一大难题。下面我们首先分析一下Observable类。

  3.Observable类的“触发-通知”原理

  Observable必须“有变化”才能触发通知observer这一任务,这是它的本质体现。查看源码便可知一二。Observerable部分源码如下:
 //……省略……
   private boolean changed = false;

   //……省略……

   public void notifyObservers(Object arg){
    //……省略……
     Object[] arrLocal;
     synchronized (this){
      //……省略……
      if (!changed)
        return;
       arrLocal = obs.toArray();
       clearChanged();
    }

   //……省略……
   protected synchronized void setChanged() {
     changed = true;
   }
 
   protected synchronized void clearChanged() {
     changed = false;
   }

    正如上所示,在notifyObservers(Object arg)方法里if(!changed) return;语句告诉我们,若changed属性值为false,将直接返回,根本不会触发通知操作。并且我们注意到changed属

性被初始化为false,这将意味着如果我们不主动设置changed属性为true,将不会有任何变化,也就是说根本起不到“通知”作用。因此,设置changed属性的值是我们应用jdk observer 

设计模式的关键所在。

    那么如何才能设置changed属性呢?从源码可以看出,唯一的入口是通过setChanged()。下面我们分析一下changed属性及相关的方法setChanged()和clearChanged()。

4.Observable类的分析

  细心的读者可能会注意到Observable中跟changed属性有关的两个方法setChanged()和clearChanged(),它们的修饰符都是protected,而不是public。但这样是否有其必要性和合理性?

答案是肯定的。在前面的分析中,已经提到,setChanged()方法是设置changed的唯一入口,它的修饰符定义为protected,就意味着不通过Observable定义的对象,设置changed属性将变得不

可能。从这个意义上说,要想应用observer设计模式,必须继承Observable类方可。

    但是,为什么不能定义成public?这似乎难以理解。因为定义成public,我们不就可以很方便地设置changed属性的值吗?为了弄清楚这个问题,我们还是看一下Observable里的相关的代

码:

  //……省略……
  public void notifyObservers(Object arg) {
  //……省略……
   for (int i = arrLocal.length-1; i>=0; i--)
    ((Observer)arrLocal[i]).update(this, arg);
  }
    
  这段代码表达的意思是找出所有已注册的Observer,再逐个通过调用Observer的update(Observable,Object)方法进行“通知”。我们看到,update方法的第一个参数是this,我们同时还

注意到,这段代码是Observable类里的代码。这就相当于是在一再强调,发出“通知”的,必须是observable(Observable类或者其派生类),其它任何类都不行。这就意味着我们的

observable类继承Observable类是必要的,因为如果不继承,而采用组合的话,将无法保证能传递好this。换句话说,采用组合的方式使用Observable类,将变得几乎没有任何意义。同时,

修饰符定义为protected,可以确保是在Observable里进行触发通知的,不会在其它任何地方进行通知,这显得内敛性很强。如果将setChanged()修饰符定义为public,将无法保证正确“传

递this”的硬性要求,即不符合“只有observalbe才能直接或间接通知observer”这一observable设计模式的硬性要求。由此我们可见一斑,jdk的很多理念的思想性是多么的强。

  5.解决使用observer设计模式存在的困难

  借助adapter设计模式和java支持多接口特性基本可以解决“多继承”问题。基本思想是结合继承/实现和组合来达到效果。在上面的分析中已经知道,Observable类必须继承使用,不能

组合使用,因此只需要将需扮演成observerable角色的类装扮成adapter角色,将该类原继承的类装扮成adapter角色即可。示例代码如下:

  //欲充当observable角色的类的原来的代码:
  public class MyObject extends BaseObject {
   public MyObject() {
    public void method1(){}
   }
  }

  //充当observable角色后的代码:
  public class MyObject extends Observable {
   private BaseObject baseObject = null;
    public MyObject(BaseObject baseObject) {
     this.baseObject = baseObject;
    }
  }