`
easonfans
  • 浏览: 254166 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

观察者模式介绍--阎宏(1)

阅读更多

观察者模式介绍

  简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象。这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的那些观察者对象,使这些观察者对象能够自动更新。

观察者模式的结构
  观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或从属者(Dependents)模式。

本模式的类图结构如下:

图1、观察者模式的静态结构可从类图中看清楚

在观察者模式里有如下的角色:
抽象主题(Subject)角色:主题角色把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。主题提供一个接口可以加上或撤销观察者对象;主题角色又叫做抽象被观察者(Observable)角色;(体会一下,是被观察者保存观察着的注册信息) 

图2、抽象主题角色,有时又叫做抽象被观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现


 

. 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到通知时更新自己;


 

图3、抽象观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现

 

. 具体主题(ConcreteSubject)角色:保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;

图4、具体主题角色,通常用一个具体子类实现

 

具体观察者(ConcreteObserver)角色:保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,以便使本身的状态与主题的状态自恰。

图5、具体观察者角色,通常用一个具体子类实现。

 

下面给出一个示意性实现的Java代码。首先在这个示意性的实现里,用一个Java接口实现抽象主题角色,这就是下面的Subject接口:

public interface Subject
{
     public void attach(Observer observer);

     public void detach(Observer observer);

     void notifyObservers();
}

 

代码清单1、Subject接口的源代码

 

  这个抽象主题接口规定出三个子类必须实现的操作,即 attach() 用来增加一个观察者对象;detach() 用来删除一个观察者对象;和notifyObservers() 用来通知各个观察者刷新它们自己。抽象主题角色实际上要求子类保持一个以所有的观察者对象为元素的列表。

 

具体主题则是实现了抽象主题Subject接口的一个具体类,它给出了以上的三个操作的具体实现。从下面的源代码可以看出,这里给出的Java实现使用了一个Java向量来保存所有的观察者对象,而 attach() 和 detach() 操作则是对此向量的元素增减操作。

import java.util.Vector;
import java.util.Enumeration;

public class ConcreteSubject implements Subject
{
     private Vector observersVector = new java.util.Vector();

     public void attach(Observer observer)
     {
          observersVector.addElement(observer);
     }

     public void detach(Observer observer)
     {
          observersVector.removeElement(observer);
     }

     public void notifyObservers()
     {
          Enumeration enumeration = observers();
          while (enumeration.hasMoreElements())
          {
               ((Observer)enumeration.nextElement()).update();
          }
     }

     public Enumeration observers()
     {
          return ((Vector) observersVector.clone()).elements();
     }
}

代码清单2、ConcreteSubject类的源代码  

 

抽象观察者角色的实现实际上是最为简单的一个,它是一个Java接口,只声明了一个方法,即update()。这个方法被子类实现后,一被调用便刷新自己。

 

public interface Observer
{
     void update();
} 

 代码清单3、Observer接口的源代码

 

具体观察者角色的实现其实只涉及update()方法的实现。这个方法怎么实现与应用密切相关,因此本类只给出一个框架。

 

public class ConcreteObserver implements Observer
{
     public void update()
     {
      // Write your code here
     }
}

 代码清单4、ConcreteObserver类的源代码

 

  虽然观察者模式的实现方法可以有设计师自己确定,但是因为从AWT1.1开始视窗系统的事件模型采用观察者模式,因此观察者模式在Java语言里的地位较为重要。正因为这个原因,Java语言给出了它自己对观察者模式的支持。因此,本文建议读者在自己的系统中应用观察者模式时,不妨利用Java语言所提供的支持。

 

在Java语言的java.util库里面,提供了一个Observable类以及一个Observer接口,构成Java语言对观察者模式的支持。

 Observer接口(观察着继承)
  这个接口只定义了一个方法,update()。当被观察者对象的状态发生变化时,这个方法就会被调用。这个方法的实现应当调用每一个被观察者对象的notifyObservers()方法,从而通知所有的观察对象。

图6、java.util提供的Observer接口的类图

 

package java.util;

public interface Observer
{
     /**
     * 当被观察的对象发生变化时,这个方法会被调用。
    */
     void update(Observable o, Object arg);
}

代码清单5、java.util.Observer接口的源代码

 

Observable类被观察者类继承

  被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类非常重要:一个是setChanged(),另一个是notifyObservers()。第一个方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己。

  java.util.Observable类还有其它的一些重要的方法。比如,观察者对象可以调用java.util.Observable类的addObserver()方法,将对象一个一个加入到一个列表上。当有变化时,这个列表可以告诉notifyObservers()方法那些观察者对象需要通知。由于这个列表是私有的,因此java.util.Observable的子对象并不知道观察者对象一直在观察着它们。

图7、Java语言提供的被观察者的类图

 被观察者类Observable的源代码:

package java.util;
public class Observable
{
     private boolean changed = false;
     private Vector obs;

     /** 用0个观察者构造一个被观察者。**/

     public Observable()
     {
          obs = new Vector();
     }

     /**
     * 将一个观察者加到观察者列表上面。
     */
     public synchronized void addObserver(Observer o)
     {
          if (!obs.contains(o))
          {
               obs.addElement(o);
          }
     }

     /**
     * 将一个观察者对象从观察者列表上删除。
     */
     public synchronized void deleteObserver(Observer o)
     {
          obs.removeElement(o);
     }

     /**
     * 相当于 notifyObservers(null)
     */
     public void notifyObservers()
     {
          notifyObservers(null);
     }

     /**
     * 如果本对象有变化(那时hasChanged 方法会返回true)
     * 调用本方法通知所有登记在案的观察者,即调用它们的update()方法,
     * 传入this和arg作为参量。
     */
     public void notifyObservers(Object arg)
     {
     /**
     * 临时存放当前的观察者的状态。参见备忘录模式。
     */
          Object[] arrLocal;

          synchronized (this)
          {
               if (!changed) return;
               arrLocal = obs.toArray();
               clearChanged();
          }

          for (int i = arrLocal.length-1; i>=0; i--)
               ((Observer)arrLocal[i]).update(this, arg);
      }

     /**
     * 将观察者列表清空
     */
     public synchronized void deleteObservers()
     {
          obs.removeAllElements();
     }

     /**
     * 将“已变化”设为true
     */
     protected synchronized void setChanged()
     {
          changed = true;
     }

     /**
     * 将“已变化”重置为false
     */
     protected synchronized void clearChanged()
     {
          changed = false;
     }

     /**
     * 探测本对象是否已变化
     */
     public synchronized boolean hasChanged()
     {
          return changed;
}

     /**
     * 返还被观察对象(即此对象)的观察者总数。
     */
     public synchronized int countObservers()
     {
          return obs.size();
     }
}

 

代码清单6、java.util.Observer接口的源代码

 

 

 

 

      这个Observable类代表一个被观察者对象。一个被观察者对象可以有数个观察者对象,一个观察者可以是一个实现Observer接口的对象。在被观察者对象发生变化时,它会调用Observable的notifyObservers方法,此方法调用所有的具体观察者的update()方法,从而使所有的观察者都被通知更新自己。见下面的类图:



 

图8、使用Java语言提供的对观察者模式的支持

 

  发通知的次序在这里没有指明。Observerable类所提供的缺省实现会按照Observers对象被登记的次序通知它们,但是Observerable类的子类可以改掉这一次序。子类并可以在单独的线程里通知观察者对象;或者在一个公用的线程里按照次序执行。

  当一个可观察者对象刚刚创立时,它的观察者集合是空的。两个观察者对象在它们的equals()方法返回true时,被认为是两个相等的对象。

 

怎样使用Java对观察者模式的支持

  为了说明怎样使用Java所提供的对观察者模式的支持,本节给出一个非常简单的例子。在这个例子里,被观察对象叫做Watched,也就是被监视者;而观察者对象叫做Watcher。Watched对象继承自java.util.Obsevable类;而Watcher对象实现了java.util.Observer接口。另外有一个对象Tester,扮演客户端的角色。

这个简单的系统的结构如下图所示:


图9、一个使用Observer接口和Observable类的例子

 

在客户端改变Watched对象的内部状态时,Watched就会通知Watcher采取必要的行动。

package com.javapatterns.observer.watching;

import java.util.Observer;

public class Tester
{
     static private Watched watched;
     static private Observer watcher;

     public static void main(String[] args)
     {
          watched = new Watched();

          watcher = new Watcher(watched);

          watched.changeData("In C, we create bugs.");
          watched.changeData("In Java, we inherit bugs.");
          watched.changeData("In Java, we inherit bugs.");
          watched.changeData("In Visual Basic, we visualize bugs."); 
     }
}

 

代码清单7、Tester类的源代码

 

package com.javapatterns.observer.watching;

import java.util.Observable;

public class Watched extends Observable
{
     private String data = "";

     public String retrieveData()
     {
          return data;
     }

     public void changeData(String data)
     {
          if ( !this.data.equals( data) )
          {
               this.data = data;
               setChanged();
          }

          notifyObservers();
     }
}  

代码清单8、Watched类的源代码

package com.javapatterns.observer.watching;

import java.util.Observable;
import java.util.Observer;

public class Watcher implements Observer
{
     public Watcher(Watched w)
     {
          w.addObserver(this);
     }

     public void update( Observable ob, Object arg)
     {
          System.out.println("Data has been changed to: '" + ((Watched)ob).retrieveData() + "'");
     }
} 

代码清单9、Watcher类的源代码

 

可以看出,虽然客户端将Watched对象的内部状态赋值了四次,但是值的改变只有三次:

watched.changeData("In C, we create bugs.");
watched.changeData("In Java, we inherit bugs.");
watched.changeData("In Java, we inherit bugs.");
watched.changeData("In Visual Basic, we visualize bugs."); 

 代码清单10、被观察者的内部状态发生了改变

 

对应地,Watcher对象汇报了三次改变,下面就是运行时间程序打印出的信息:

 

Data has been changed to: 'In C, we create bugs.'
Data has been changed to: 'In Java, we inherit bugs.'
Data has been changed to: 'In Visual Basic, we visualize bugs.'

 

 

代码清单11、运行的结果

 

代码清单11、运行的结果

 

 

分享到:
评论

相关推荐

    java与模式-阎宏

    4. 行为型模式:包括职责链模式、命令模式、解释器模式、迭代器模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。行为型模式关注于对象之间的交互和行为,帮助我们更好地管理复杂的...

    Java与模式(阎宏)高清晰完整PDF版

    除了这些,书中还涵盖了其他多种设计模式,如单例模式(确保一个类只有一个实例,并提供一个全局访问点)、建造者模式(将复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示)、观察者模式(定义...

    《Java 与模式》作者阎宏博士(PDF).rar

    例如,工厂模式用于创建对象,单例模式确保类只有一个实例,观察者模式则实现了对象之间的依赖关系管理。 书中不仅涵盖了创建型、结构型和行为型三大类设计模式,还讨论了如何在实际项目中选择和组合不同的模式,...

    源码:阎宏设计模式光盘

    com.javapatterns.observerawt 专题:观察者模式与AWT中的事件处理 com.javapatterns.observersax 专题:观察者模式与SAX2浏览器 com.javapatterns.observertimer 专题:观察者模式与Swing定时器 ...

    Java与模式(阎宏)

    - **观察者模式**:定义对象间的一种一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。 - **模板方法模式**:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。使得...

    java与模式光盘源码

    例如,观察者模式在事件驱动编程中非常常见,它使得多个对象能监听某个对象的状态变化并作出相应反应。而策略模式则常用于算法的封装和选择,允许在运行时动态切换不同的算法策略。 总的来说,《Java与模式》光盘...

    《Java与模式 阎宏 摘录》.doc 更新中……

    阎宏在书中详细解析了多个经典设计模式,如单例模式、工厂模式、观察者模式、装饰器模式等。这些模式都是在实际项目中不可或缺的工具,能帮助我们编写出可维护、可扩展的代码。 单例模式确保一个类只有一个实例,并...

    Java与模式(阎宏著)源码

    4. **行为型模式**:这些模式关注对象间如何交互和分配责任,如命令模式(Command)、解释器模式(Interpreter)、迭代器模式(Iterator)、备忘录模式(Memento)、观察者模式(Observer)、状态模式(State)、...

    Java与模式(阎宏经典版)

    本书涵盖了如单例模式、工厂模式、观察者模式、装饰器模式等多种经典设计模式。这些模式不仅适用于Java,也广泛应用于Android开发,因为Android框架本身大量运用了设计模式。 1. **单例模式**:确保一个类只有一个...

    java与模式

    行为型模式如策略(Strategy)、观察者(Observer)、职责链(Chain of Responsibility)等,主要涉及对象间的行为和交互。 本书详尽地阐述了这些模式的原理、应用场景以及Java实现方式。例如,工厂方法模式通过...

    Java设计模式

    例如,工厂模式可以帮助我们解耦对象的创建和使用,单例模式保证了全局只有一个实例,而观察者模式则实现了对象之间的发布-订阅关系。通过学习《Java与模式》中阎宏先生的讲解,开发者可以深入理解这些模式的内在...

    java 与 模式 闫宏 pdf

    书中详细介绍了如工厂模式、单例模式、观察者模式、装饰器模式等23种经典设计模式,并结合Java语言特性进行讲解。 2. **面向对象设计原则**:包括单一职责原则(SRP)、开放封闭原则(OCP)、里氏替换原则(LSP)、...

    闫宏Java设计模式源码

    6. **观察者模式**:定义对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。Java中Observer接口和Observable类就是这种模式的体现。 7. **装饰器模式**:动态地给一...

    Java与模式(清晰书签版)【阎宏著】和本书源代码

    包括创建型模式(如单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式)、结构型模式(如代理模式、适配器...观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式和解释器模式)...

    Java与模式(高清版)

    3. **行为型模式**:如策略模式、模板方法模式、观察者模式、命令模式、迭代器模式、责任链模式、备忘录模式、解释器模式、状态模式和访问者模式。这些模式关注的是对象的行为和交互,帮助我们更好地组织代码,实现...

    Java与模式(清晰书签版)

    阎宏的《Java与模式》涵盖了23种GOF(GoF,Gang of Four)设计模式,这些模式是面向对象设计的核心部分,包括工厂模式、单例模式、观察者模式、装饰器模式等。 书中详细阐述了每一种模式的意图、结构、参与者以及...

    23种设计模式Java代码

    - **观察者模式**:定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。 - **解释器模式**:给定一个语言,定义它的文法的一种表示,并提供一个解释器。 ...

    java与模式源码

    本书涵盖了众多经典的设计模式,如单例模式、工厂模式、观察者模式、装饰器模式、适配器模式、代理模式等,每种模式都结合了实际的Java代码示例进行详细阐述。 设计原则是指导我们编写高质量代码的基石,包括开闭...

    Java设计模式(第三部分)

    在提供的压缩包文件中,包含了该书的部分章节,如part11至part15,这可能包括了状态模式、观察者模式、装饰器模式、策略模式、代理模式等。下面将对这些设计模式进行详述: 1. **状态模式**:允许对象在其内部状态...

Global site tag (gtag.js) - Google Analytics