一、简介
观察者设计模式有如下四个角色
- 抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类或接口来实现,也可以使用非抽象类来实现。
- 具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
- 抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
- 具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。通常用一个子类实现。
观察者设计模式类图如下:
二、java JDK中对观察者的支持
java JDK中提供了Observer 与 Observable两个类。Observer类可以看作是抽象观察者角色,而Observable是抽象主题角色。
1、Objserver
Objserver 是个接口,代码如下:
public interface Observer { /** * 该方法当主题对象发生改变的时候被调用. An * 一个应用调用主题对象的notifyObservers方法来application calls an <tt>Observable</tt> object's * <code>notifyObservers</code> method to have all the object's * observers notified of the change. * * @param o the observable object. * @param arg an argument passed to the <code>notifyObservers</code> * method. */ void update(Observable o, Object arg); }
它只提供了一个update,让子类去实现。当主题对象发生改变的时候,就会调用观察者对象的update方法,从而达到观察者发生改变的目的。
2、Observable
Observable是个类,代码如下:
public class Observable { private boolean changed = false; private Vector obs;//用于存放观察者对象的引用 public Observable() { obs = new Vector(); } //添加一个观察者 public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } //移除一个观察者 public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } //通知所有观察者 public void notifyObservers() { notifyObservers(null); } //通知指定的观察者 public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed)//当状态没有发生改变的时候,直接返回 return; arrLocal = obs.toArray(); clearChanged(); } //通知并调用观察者的update方法 for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } //移除所有观察者 public synchronized void deleteObservers() { obs.removeAllElements(); } //设置状态改变 protected synchronized void setChanged() { changed = true; } //重置状态 protected synchronized void clearChanged() { changed = false; } //判断是否状态是否发生改变 public synchronized boolean hasChanged() { return changed; } 返回观察者的个数 public synchronized int countObservers() { return obs.size(); } }
从代码可以看出,我们可以让具体主题对象继承Observable类,具体观察者对象实现Observer接口并实现update方法。调用的时候只需要实例化具体主题对象与具体观察者对象,然后将具体观察者对象添加到具体主题对象中的obs(Vector)列表。当具体主题对象的状态发生该变时,调用观察者对象的update方法(这里状态发生该变指的是调用主题对象的某个方法,该方法里面有对具体观察者对象的update方法的调用)。
三、实例
具体观察者对象
具体主题对象 package com.observer; import java.util.Observable; /** * 具体主题对象 * */ public class ConcreteSubject extends Observable { private String info; public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } public void doSomething(String str) { System.out.println("subject: " + str); setInfo(str); setChanged();//改变主题对象的状态,这里如果不改变它的状态,则不会对观察者对象调用update方法 // notifyObservers();//也可以不传递参数 notifyObservers("subject is changed");//这里传递的参数是观察者对象中update方法参数列表中的第二个参数 } }
具体观察者对象
package com.observer; import java.util.Observable; import java.util.Observer; /** * 具体观察者对象 * */ public class ConcreteObserver implements Observer { /** * @param subject 具体主题对象 * @param arg notifyObservers(String str) 传递的参数 */ public void update(Observable o, Object arg) { System.out.println(arg); ConcreteSubject subject = (ConcreteSubject)o; System.out.println("observer: " + subject.getInfo()); } }
调用代码:
package com.observer; import java.util.Observer; public class Test { public static void main(String[] args) { //观察者对象 Observer observer = new ConcreteObserver(); Observer observer2 = new ConcreteObserver(); Observer observer3 = new ConcreteObserver(); //主体对象 ConcreteSubject observable = new ConcreteSubject(); //观察者加入主题对象汇总的观察者列表 observable.addObserver(observer); observable.addObserver(observer2); observable.addObserver(observer3); //主体对象发生改变 observable.doSomething("happy"); observable.doSomething("sad"); } }