`

深度探索观察者模式

阅读更多

在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类中。

  • 大小: 40.1 KB
  • 大小: 54.2 KB
4
0
分享到:
评论
2 楼 kevindude 2010-04-23  
你说的很对,这里确实是我的疏忽,Observable.ObserverOp应该换成 ObserverList.ObserverOp
1 楼 萧十一狼 2010-04-23  
解决的办法是取消Observable接口和DefaultObservable类,使用一个ObserversList来代替,在Session中直接维护一个ObserversList,那么在逻辑上Session自然就成了一个被观察者。

那你下面的代码中的:

 public void notifyObservers(Observable.ObserverOp<T> obop) { 
 private class Notifier implements Observable.ObserverOp<SessionObserver>{   


Observable.ObserverOp应该换成 ObserverList.ObserverOp

ObserverList应该代替了Observable.

相关推荐

    观察者模式delphi代码

    观察者模式最好的诠释 模式编程中的观察者模式delphi代码

    Delphi 深度探索(第二版)〖含随书光盘源代码〗

    6.3.4 观察者模式(observer模式) 6.3.5 命令模式(command模式) 6.3.6 备忘录模式(memento模式) 6.3.7 迭代子模式(iterator模式) 6.3.8 访问者模式(visitor模式) 6.3.9 调停者模式(mediator模式) ...

    二十三种设计模式【PDF版】

    设计模式之 Observer(观察者) 介绍如何使用 Java API 提供的现成 Observer 设计模式之 Iterator(迭代器) 这个模式已经被整合入Java的Collection.在大多数场合下无需自己制造一个Iterator,只要将对象装入...

    asp.net知识库

    深度解析Asp.Net2.0中的Callback机制 使用 Web 标准生成 ASP.NET 2.0 Web 站点 ASP.NET 2.0基于SQLSERVER 2005的aspnetdb.mdf部署 ASP.NET 2.0 Security FAQs Asp.net 2.0功能体验,细节之Web控件(一) 隐藏控件 ...

    精通并发与netty视频教程(2018)视频教程

    74_Netty对于异步读写操作的架构思想与观察者模式的重要应用 75_适配器模式与模板方法模式在入站处理器中的应用 76_Netty项目开发过程中常见且重要事项分析 77_Java NIO Buffer总结回顾与难点拓展 78_Netty数据容器...

    精通并发与 netty 视频教程(2018)视频教程

    Channel选择器工厂与轮询算法及注册底层实现 72_Netty线程模型深度解读与架构设计原则 73_Netty底层架构系统总结与应用实践 74_Netty对于异步读写操作的架构思想与观察者模式的重要应用 75_适配器模式与模板方法模式...

    精通并发与netty 无加密视频

    第74讲:Netty对于异步读写操作的架构思想与观察者模式的重要应用 第75讲:适配器模式与模板方法模式在入站处理器中的应用 第76讲:Netty项目开发过程中常见且重要事项分析 第77讲:Java NIO Buffer总结回顾与...

    关于什么是大数据和数据分析?.pdf

    对于这一问题,答案是多种多样的,此文分别从实践者,观察者和预言者三种角度来分析,看完会对 您有所启发。 观点 1,实践者的角度来看: 大数据 - 表示数据的几个维度 - 可用数据的多样性,速度,体积和可信度。...

    计算机教学的课程设计.docx

    根据计算机学科的特点,结合我校长期实践探索总结出的"四主四环"的教学理念——在课堂教学的实施过程中,建立以教师为主导,以学生为主体,为训练为主线,以延伸为主旨的教学模式。一般上计算机课,我把课程分为以下...

    数据之舞:大数据与数据挖掘.doc

    威斯康星探索学院主任大卫·克拉考尔(David Krakauer)说,数据量的增长——以及提取信息的能力的提高——也在影响着科学。"计算机 的处理能力和存储空间在呈指数增长,成本却在指数级下降。从这个意义上来讲,很...

Global site tag (gtag.js) - Google Analytics