深度探索观察者模式

在GOF的设计模式一书中将观察者定义为一种对象的行为模式,又叫做发布-订阅模式(Publish/Subscribe)、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

 

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。

 

Java的标准库中包含了一个Observer接口和一个Observable类。

Observer接口很简单,只包含了一个update方法:

 

public interface Observer {
    void update(Observable o, Object arg);
}

 

 

Observable类的大纲如下 

 

 

Observable类自身维护了一个包含Observer的列表,和一个表示自身状态的changed标志,当自身状态发生变化时就调用notifyObservers通知所有注册的观察者。notifyObservers方法通过对调用每一个成员的Observer接口的update方法来实现对观察者的通知。

 

使用这种模式的例子在网上已经有很多了,这里不再具体举例,但需要指出的是在客户代码使用Java标准库提供的Observer/Observable对来实现观察者模式时需要自己编写一个继承Observable类的被观察者和一个实现Observer接口的观察者。这种方式有一个缺陷,因为Java语言是单继承的,一旦客户代码中的被观察者已经继承了一个其他的类则无法再次继承Observable类,这也大大的限制了这种模式的广泛使用。

 

在GOF一书中则描述了另一种使用观察者的模式,即将观察者和被观察者全部做成抽象接口,下面是这种模式的静态类图。

 

 

抽象被观察者提供注册和删除观察者对象的接口,一个通知观察者的接口。抽象观察者在被观察者状态发生变化并得到通知时提供一个更新自己的接口。具体被观察者和具体观察者是对抽象接口的具体实现。其中具体被观察者维护一个所有注册的观察者的列表,而观察者的update方法接受一个指向被观察者的引用。

 

观察者模式所适用的一个很重要的场景是当一个对象必须通知其他对象,而它又不能假定其它对象是谁。也就是说,你不希望这些对象是紧密耦合的。这里通过使用接口来达到解耦的目的。这种观察者模式的应用使用接口而不是类解决了Java单继承的问题,这种模型通过GOF一书而得到广为流传,网络上的例子很多,这里也不具体举例了。但是我们也看到,由于Observer接口只有一个update方法,也就说是当观察者接受到通知它只能作出同样的回应。在一个事件-触发模型中,由于观察者(或者说事件监听者)需要对不同的事件作出回应,那这种模型就不再适用。就算用起来也会显得很繁琐,比如在具体观察者的update方法中指定参数类型,或者使用反射,又或者传入一个参数来表明事件的类型,但不论如何都不是一种很好的实现方式。而可以复用的只有两个接口,每次使用的时候必须要实现两个具体类,没能达到很高的复用性。

 

下面介绍一种新的Observer模式的实现方法。这里使用了泛型模板,通过参数化Observer接口来实现任意定制更新方法。另外还引入了一个ObserverOp的接口,将Observer Operation的操作抽象,使得观察者与被观察者解耦。

/** Observable接口代码 */

public interface Observable<T> {
 
    public static interface ObserverOp<T>
    {
        public void apply (T observer);
    }
 
 public void addObserver(T observer);
 public void deleteObserver(T observer);
 public void notifyObservers(ObserverOp<T> obop);

}

  

每一个被观察者都要实现这个接口则显得比较繁琐,所以这里提供了一个默认实现。

/** Observable接口的默认实现代码 */

public class DefaultObservable<T> implements Observable<T> {

 private List<T> obs;;
 
 public DefaultObservable(){
  obs = new ArrayList<T>();
 }
  public void addObserver(T observer) {
  obs.add(observer);

 }

 
 public void deleteObserver(T observer) {
  obs.remove(observer);

 }

  public void notifyObservers(Observable.ObserverOp<T> obop) {
  Iterator<T> iterator = obs.iterator();
  while (iterator.hasNext()){
   obop.apply(iterator.next());
  }

 }

}

 

下面举例说明这种观察者模式的使用,假如我们有一个Session类,当Session的状态发生变化时需要通知客户代码,并假设状态的变化有激活和静默两种,这样我们就有了一个SessionObserver接口。

 

/** SessionObserver接口的代码 */

public interface SessionObserver {
 public void SessionActivate(Session session);
 public void SessionPassivate(Session session);

}

 
 

同时我们也有一个对应的Session类。

/** Session类的代码 */

public class Session {

 private Observable<SessionObserver> obs = new DefaultObservable<SessionObserver>();
 public void addSessionObserver(SessionObserver observer){
  obs.addObserver(observer);
 }
 
 public void Activate(){
  //do activate
  Notifier noty = new Notifier(SESSION_ACTIVATE);
  obs.notifyObservers(noty);
 }
 
 public void Passivate(){
  //do passivate
  Notifier noty = new Notifier(SESSION_PASSIVATE);
  obs.notifyObservers(noty);
 }
 
 private class Notifier implements Observable.ObserverOp<SessionObserver>{
  private int code;
  public Notifier(int code){
   this.code=code;
  }
  public void apply(SessionObserver obs){
   switch (code){
   case SESSION_ACTIVATE:
    obs.SessionActivate(Session.this);
    break;
   case SESSION_PASSIVATE:
    obs.SessionPassivate(Session.this);
    break;
   }
  }
 }
 
 public static final int SESSION_ACTIVATE = 1;
 public static final int SESSION_PASSIVATE = 2;

}

 

在这里我们内置了一个Notifier类,这个类实现了ObserverOp接口,将我们所有的Observer Operation操作都包含了进去,使得其余部分的代码十分简洁。在这里Notifier类实际上实现了设计模式中另一个strategy(策略)模式,这个stragety(策略)将相关的操作算法封装在了一个类里。对于不同的Observer接口可以十分方便的替换我们的算法。下面是客户代码,当Session被激活或者静默时客户代码被自动通知并作出反应。

 

/** 客户代码 */

public class Client implements SessionObserver {

  public void SessionActivate(Session session) {
  System.out.println("Session has been activated...");

 }

  public void SessionPassivate(Session session) {
  System.out.println("Session has been passivated...");

 }
 
 public static void main (String[] args){
  Client client = new Client();
  Session session = new Session();
  session.addSessionObserver(client);
  session.Activate();
  session.Passivate();
 } 
}

  

通过观察上面的例子我们可以看到,使用这种观察者模式的模型,当被观察者被通知时,可以根据通知的内容调用相应的方法,在这里就是当Session被激活时调用SessionActivate方法,当Session被静默时调用SessionPassivate方法,而不仅仅是一个简单的update方法。但是这种模型也有一个问题,就是在这里Session是一个被观察者的身份,但是因为使用了泛型的模板而无法继承DefaultObservable类,或实现Observable接口,使得IS-A关系变成了HAS-A,逻辑上不是那么的清晰。解决的办法是取消Observable接口和DefaultObservable类,使用一个ObserversList来代替,在Session中直接维护一个ObserversList,那么在逻辑上Session自然就成了一个被观察者。

 

下面我们来看下新模型下的ObserversList类和修改过的Session类。

 

/** ObserverList的实现代码 */

public class ObserverList<T> extends ArrayList<T> {

    public static interface ObserverOp<T>
    {
        public void apply (T observer);
    }
    
    public void addObserver(T observer){
     add(observer);
    }
    
    public void deleteObserver(T observer){
     remove(observer);
    }
    
 public void notifyObservers(Observable.ObserverOp<T> obop) {
        int count = size();
  if (obs == null ){
         obs = (T[])new Object[count];
        }
  toArray(obs);
  for(int i=0;i<count;i++){
   obop.apply(obs[i]);
  }
 }
 
 private T[] obs;
}


/** 修改过的Session类的实现代码 */

public class Session {

 private ObserverList<SessionObserver> obs = new ObserverList<SessionObserver>();
 
 public void addSessionObserver(SessionObserver observer){
  obs.addObserver(observer);
 }
 
 public void Activate(){
  //do activate
  Notifier noty = new Notifier(SESSION_ACTIVATE);
  obs.notifyObservers(noty);
 }
 
 public void Passivate(){
  //do passivate
  Notifier noty = new Notifier(SESSION_PASSIVATE);
  obs.notifyObservers(noty);
 }
 
 private class Notifier implements Observable.ObserverOp<SessionObserver>{
  private int code;
  public Notifier(int code){
   this.code=code;
  }
  public void apply(SessionObserver obs){
   switch (code){
   case SESSION_ACTIVATE:
    obs.SessionActivate(Session.this);
    break;
   case SESSION_PASSIVATE:
    obs.SessionPassivate(Session.this);
    break;
   }
  }
 }
 
 public static final int SESSION_ACTIVATE = 1;
 public static final int SESSION_PASSIVATE = 2;

}

  

在这个新的模型下,ObserverList继承自ArrayList,而Session类里维护了这个包含所有观察者的列表,所以在逻辑上自然而然的成立了IS-A Observable的关系,其他代码都维持不变。现在ObserverList类可以被放到通用的类库中被反复使用,而客户则可以根据需要定制自己的Observer接口,并将相对应的算法操作封装在一个具体的ObserverOp类中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章