先跳过理论,JDK中已经实现了观察者模式的框架,我们先看下是如何使用的,接着看下JDK中是如何设计的,最后来自己实现观察者模式及其理论介绍
1.如何用
1 public class Guanchazhe { 2 3 public static void main(String[] args) { 4 Watched watched = new Watched(); 5 Watcher watcher = new Watcher(watched); 6 watched.setData("start"); 7 watched.setData("run"); 8 watched.setData("stop"); 9 } 10 } 11 12 // 被观察者 13 class Watched extends Observable { 14 private String data; 15 16 public Watched() { 17 18 } 19 20 public String getData() { 21 return data; 22 } 23 24 public void setData(String data) { 25 this.data = data; 26 setChanged(); 27 this.notifyObservers(); 28 29 } 30 31 } 32 33 class Watcher implements Observer { 34 35 public Watcher(Observable observable) { 36 37 observable.addObserver(this); 38 } 39 40 public void update(Observable o, Object arg) { 41 Watched watched = (Watched) o; 42 System.out.println(watched.getData()); 43 44 } 45 46 }
打印结果:
start
run
stop
总结:观察者Watcher 实现Observer接口,而被观察者继承Watched ,当Watched 的状态改变的时候,先setChanged(),再调用notifyObservers().
接下来分析下notifyObservers()方法
1 public void notifyObservers() { 2 notifyObservers(null); 3 } 4 5 public void notifyObservers(Object arg) { 6 /* 7 * a temporary array buffer, used as a snapshot of the state of 8 * current Observers. 9 */ 10 Object[] arrLocal; 11 12 synchronized (this) { 13 14 if (!changed) 15 return; 16 arrLocal = obs.toArray(); 17 clearChanged(); 18 } 19 20 for (int i = arrLocal.length-1; i>=0; i--) 21 ((Observer)arrLocal[i]).update(this, arg); 22 }
通过notifyObservers()方法去唤醒观察者中重写的update()方法,至于每个观察者,则是通过this来确定的,而arg则为被观察者对应的参数,可以为空
2.JDK的实现代码
1 public interface Observer { 2 /** 3 * This method is called whenever the observed object is changed. An 4 * application calls an <tt>Observable</tt> object‘s 5 * <code>notifyObservers</code> method to have all the object‘s 6 * observers notified of the change. 7 * 8 * @param o the observable object. 9 * @param arg an argument passed to the <code>notifyObservers</code> 10 * method. 11 */ 12 void update(Observable o, Object arg); 13 }
1 public class Observable { 2 private boolean changed = false; 3 private Vector obs; 4 5 6 public Observable() { 7 obs = new Vector(); 8 } 9 10 11 public synchronized void addObserver(Observer o) { 12 if (o == null) 13 throw new NullPointerException(); 14 if (!obs.contains(o)) { 15 obs.addElement(o); 16 } 17 } 18 19 20 public synchronized void deleteObserver(Observer o) { 21 obs.removeElement(o); 22 } 23 24 25 public void notifyObservers() { 26 notifyObservers(null); 27 } 28 29 30 public void notifyObservers(Object arg) { 31 32 Object[] arrLocal; 33 34 synchronized (this) { 35 36 if (!changed) 37 return; 38 arrLocal = obs.toArray(); 39 clearChanged(); 40 } 41 42 for (int i = arrLocal.length-1; i>=0; i--) 43 ((Observer)arrLocal[i]).update(this, arg); 44 } 45 46 47 public synchronized void deleteObservers() { 48 obs.removeAllElements(); 49 } 50 51 52 protected synchronized void setChanged() { 53 changed = true; 54 } 55 56 57 protected synchronized void clearChanged() { 58 changed = false; 59 } 60 61 62 public synchronized boolean hasChanged() { 63 return changed; 64 } 65 66 67 public synchronized int countObservers() { 68 return obs.size(); 69 } 70 }
3.自己实现
略
4.理论部分
在阎宏博士的《JAVA与模式》一书中开头是这样描述观察者(Observer)模式的:
观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式的结构
一个软件系统里面包含了各种对象,就像一片欣欣向荣的森林充满了各种生物一样。在一片森林中,各种生物彼此依赖和约束,形成一个个生物链。一种生物的状态变化会造成其他一些生物的相应行动,每一个生物都处于别的生物的互动之中。
同样,一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其他的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。
下面以一个简单的示意性实现为例,讨论观察者模式的结构。
观察者模式所涉及的角色有:
● 抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。
● 具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。
● 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。
● 具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。