JAVA设计模式学习19——观察者模式

2019-03-13 23:38|来源: 网络

观察者(Observer)模式:是对象的行为模式,又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听(Source/Listener)模式或者从属(Dependents)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。    
观察者模式类的结构:    
 观察者模式角色如下:
     抽象主题(Subject)角色:抽象主题角色提供维护一个观察者对象聚集的操作方法,对聚集的增加、删除等。
     具体主题(ConcreteSubject)角色:将有关状态存入具体的观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色负责实现抽象主题中聚集的管理方法。
     抽象观察者(Observer)角色:为具体观察者提供一个更新接口。
     具体观察者(ConcreteObserver)角色:存储与主题相关的自洽状态,实现抽象观察者提供的更新接口。
   
 仔细观察上面的类图,发现具体主题角色和抽象观察者之间的连线,是因为具体主题角色维护了一个观察者引用的聚集,如果有多个具体主题角色,意味着每个具体角色都要维护一个观察者的聚集,那么能不能将聚集提升到抽象主题里面呢?这个就需要考虑场景,如果多个主题实现在管理上都有很大差异,那么就不能提升到抽象角色中,但是绝大多数情况下,这些聚集管理方法本身就是所有具体主题所共有的,所以大多数情况下都是可以将聚集和聚集的管理都移入到抽象主题中的,因为notifyObserver()方法是依赖于聚集的,所以将notifyObserver()也移入抽象主题中,这样就形成了如下的另一种观察者模式结构:

我们这里简单用代码描述如下:    
   
Java代码
  1. package observer.desc;  

  2. /**

  3. *

  4. *作者:alaric

  5. *时间:2013-8-13下午8:05:08

  6. *描述:抽象观察者

  7. */  

  8. public interface Observer {  

  9.    public void update();  

  10. }  

Java代码
  1. package observer.desc;  

  2. /**

  3. *

  4. *作者:alaric

  5. *时间:2013-8-13下午8:05:34

  6. *描述:具体观察者

  7. */  

  8. public class ConcreteObserver implements Observer{  

  9.  

  10.    @Override  

  11.    public void update() {  

  12.        // 写业务逻辑  

  13.    }  

  14. }  

Java代码
  1. package observer.desc;  

  2. /**

  3. *

  4. *作者:alaric

  5. *时间:2013-8-13下午8:05:55

  6. *描述:抽象主题

  7. */  

  8. public interface Subject {  

  9.  

  10.    public void attach(Observer observer);  

  11.  

  12.    public void detach(Observer observer);  

  13.  

  14.    void notifyObservers();  

  15. }  

Java代码
  1. package observer.desc;  

  2.  

  3. import java.util.Enumeration;  

  4. import java.util.Vector;  

  5. /**

  6. *

  7. *作者:alaric

  8. *时间:2013-8-13下午8:09:21

  9. *描述:具体主题类

  10. */  

  11. public class ConcreteSubject implements Subject {  

  12.    private Vector<Observer>observersVector = new Vector<Observer>();  

  13.    public void attach(Observer observer) {  

  14.        observersVector.addElement(observer);  

  15.    }  

  16.  

  17.    public void detach(Observer observer) {  

  18.        observersVector.removeElement(observer);  

  19.    }  

  20.  

  21.    public void notifyObservers() {  

  22.        Enumeration<Observer>enumeration = observers();  

  23.        while (enumeration.hasMoreElements()) {  

  24.            ((Observer) enumeration.nextElement()).update();  

  25.        }  

  26.    }  

  27.  

  28.    @SuppressWarnings("unchecked")  

  29.    public Enumeration<Observer> observers() {  

  30.        return ((Vector<Observer>) observersVector.clone()).elements();  

  31.    }  

  32. }  


上面代码描述第一种形式,第二种读者可以自己实现,这里不再赘述。    
接下来我们看java语言是如何支持观察者模式的,java提供一个被观察者类java.util.Observable和一个观察者接口java.util.Observer。    

jdk1.6中API文档如下描述:

   

public interface Observer

   

一个可在观察者要得到 observable 对象更改通知时可实现 Observer 接口的类。

   

从以下版本开始:

   

JDK1.0

   

另请参见:

   

Observable

   

public class Observableextends Object

   

此类表示模型视图范例中的 observable 对象,或者说“数据”。可将其子类化,表示应用程序想要观察的对象。

   

一个 observable 对象可以有一个或多个观察者。观察者可以是实现了 Observer 接口的任意对象。一个 observable 实例改变后,调用 Observable 的 notifyObservers 方法的应用程序会通过调用观察者的 update 方法来通知观察者该实例发生了改变。

   

未指定发送通知的顺序。Observable 类中所提供的默认实现将按照其注册的重要性顺序来通知 Observers,但是子类可能改变此顺序,从而使用非固定顺序在单独的线程上发送通知,或者也可能保证其子类遵从其所选择的顺序。

   

注意,此通知机制与线程无关,并且与 Object 类的 wait 和 notify 机制完全独立。 新创建一个 observable 对象时,其观察者集是空的。当且仅当 equals 方法为两个观察者返回 true 时,才认为它们是相同的。

   

从以下版本开始:

   

JDK1.0

   

另请参见:

   

notifyObservers(), notifyObservers(java.lang.Object), Observer, Observer.update(java.util.Observable, java.lang.Object)

   

举个例子,如果你看过TVB的警匪片,你就知道卧底的工作方式。一般一个警察可能有几个卧底,潜入敌人内部,打探消息,卧底完全靠他的领导的指示干活,领导说几点行动,他必须按照这个时间去执行,如果行动时间改变,他也要立马改变自己配合行动的时间。领导派两个卧底去打入敌人内部,那么领导相当于抽象主题,而督察警官张三这个人派了两个卧底李四和万王五,张三就相当于具体主题,卧底相当于抽象观察者,这两名卧底是李四和王五就是具体观察者,派的这个动作相当于观察者在主题的登记。那么这个类图如下:    
利用javaAPI来实现,代码描述如下:    
Java代码
  1. package observer;  

  2.  

  3. import java.util.List;  

  4. import java.util.Observable;  

  5. import java.util.Observer;  

  6. /**

  7. *

  8. *作者:alaric

  9. *时间:2013-8-13下午9:32:40

  10. *描述:警察张三

  11. */  

  12. public class Police extends Observable {  

  13.  

  14.    private String time ;  

  15.    public Police(List<Observer> list) {  

  16.        super();  

  17.        for (Observer o:list) {  

  18.            addObserver(o);  

  19.        }  

  20.    }  

  21.    public void change(String time){  

  22.        this.time = time;  

  23.        setChanged();  

  24.        notifyObservers(this.time);  

  25.    }  

  26. }  

Java代码
  1. package observer;  

  2.  

  3. import java.util.Observable;  

  4. import java.util.Observer;  

  5. /**

  6. *

  7. *作者:alaric

  8. *时间:2013-8-13下午9:32:59

  9. *描述:卧底A

  10. */  

  11. public class UndercoverA implements Observer {  

  12.  

  13.    private String time;  

  14.    @Override  

  15.    public void update(Observable o, Object arg) {  

  16.        time = (String) arg;  

  17.        System.out.println("卧底A接到消息,行动时间为:"+time);  

  18.    }  

  19. }  

Java代码
  1. package observer;  

  2.  

  3. import java.util.Observable;  

  4. import java.util.Observer;  

  5. /**

  6. *

  7. *作者:alaric

  8. *时间:2013-8-13下午9:33:14

  9. *描述:卧底B

  10. */  

  11. public class UndercoverB implements Observer {  

  12.    private String time;  

  13.    @Override  

  14.    public void update(Observable o, Object arg) {  

  15.        time = (String) arg;  

  16.        System.out.println("卧底B接到消息,行动时间为:"+time);  

  17.    }  

  18. }  

Java代码
  1. package observer;  

  2.  

  3. import java.util.ArrayList;  

  4. import java.util.List;  

  5. import java.util.Observer;  

  6. /**

  7. *

  8. *作者:alaric

  9. *时间:2013-8-13下午9:32:26

  10. *描述:测试

  11. */  

  12. public class Client {

  13.    /**

  14.     * @param args

  15.     */  

  16.    public static void main(String[] args) {  

  17.        UndercoverA o1 = new UndercoverA();  

  18.        UndercoverB o2 = new UndercoverB();  

  19.        List<Observer> list = new ArrayList<>();  

  20.        list.add(o1);  

  21.        list.add(o2);  

  22.        Police subject = new Police(list);  

  23.        subject.change("02:25");  

  24.        System.out.println("===========由于消息败露,行动时间提前=========");  

  25.        subject.change("01:05");

  26.    }

  27. }  


测试运行结果:

卧底B接到消息,行动时间为:02:25

   

卧底A接到消息,行动时间为:02:25

   

===========由于消息败露,行动时间提前=========

   

卧底B接到消息,行动时间为:01:05

   

卧底A接到消息,行动时间为:01:05

   
观察者模式的优点是只要订阅/登记了之后,当被观察者改变时,观察者能自动更新。跟JMS一样,消息发布者发出消息时,只要注册过的都会收到消息。    
     

 
转自:http://alaric.iteye.com/blog/1924169

相关问答

更多
  • 其实我相信你做了3年的java一定了解你所说的设计模式和反射机制在程序早已用过了的把,只是自己平时没注意;设计模式主要是用项目管理,让人看起来通俗易懂.反射机制用到的地方呢也比较多,在用properties和JFreeChart等地方都用到.
  • 第一个 public interface RandomNumberListener {//接口 public void numberChanged(double d); } 第二个 public class Consol implements RandomNumberListener{ @Override public void numberChanged(double d) { System.out.println(d); } } 第三个 public class SwingWindow extends ...
  • 你可以在pull模式下使用观察者模式,这意味着observable会将自己传递给观察者的update() 。因此,观察者可以从observable的getter获取他们想要的属性。 我假设temperature , dayInTime ,你主题的season都是int 所以,你的Observable (即主题)将如下所示: public class Subject extends Observable{ private int temperature; private int dayInT ...
  • 如果要求对象是可序列化的,则它将在接口定义中声明为这样。 如: public void update(Observable observable, final Serializable observation) 但事实并非如此,因此不存在这样的要求。 If there was a requirement for the object to be serializable, it would have been declared as such in the interface definition. A ...
  • 经典的设计模式不涉及并行和线程。 你必须为N个观察者产生N个线程。 但要小心,因为它们之间的交互必须以线程安全的方式完成。 Classic design patterns do not involve parallelism and threading. You'd have to spawn N threads for the N observers. Be careful though since their interaction to this will have to be done in a t ...
  • 你的问题是比较苹果和梨。 观察者模式是问题的解决方案。 它没有告诉你如何实现解决方案,但更像是蓝图。 因此,.NET中的事件模型是观察者模式的实现。 EventHandler委托定义观察者, event关键字负责处理主题中的所有通知,正如观察者模式中所定义的那样。 Your question is comparing apples and pears. The observer pattern is a solution to a problem. It doesn't tell you how to im ...
  • 观察者模式仍然适合。 但是模式不是一成不变的,如果你不需要一组观察者,你可以简化一下:实现观察者 - >主题关联为1:1 The observer pattern still suits. But patterns are not set in stone, you can simplify it a bit if you don't need a collection of observers: implement the observer-->subject association as 1:1
  • 第二个例子看起来不错,但我不确定是否在OrderItemPickObserver类的update方法中创建新的Position对象。 相反,我建议将Position对象保持为OrderItem类的属性,以便您可以从外部设置它。 class OrderItem extends Observable { private $_position; public function setPosition($position){ $this->_posit ...
  • 是的,实施方式不同。 但! 模式是概念,而不是实现。 而且这个概念是一样的。 在这两种情况下,观察者都会参考观察到的项目,但你绝对可以想象观察者根本不需要这个参考的情况。 因此,这里的概念是“当某些东西改变状态或以某种方式执行时会收到通知”,并且它比任何实现都要广泛得多。 Yes, the implementations differ. BUT! The pattern is the concept, not the implementation. And the concept is the same. ...