public interface Subject{ // registerObserver和removeObserver都需要一个观察者作为变量,该观察者是用来注册或被删除的 void registerObserver(Observer o); void removeObserver(Observer o); // 当主题状态改变时。这个方法会被调用,以通知所有的观察者 void notifyObservers(); }具体的实现类:
// WeatherData现在实现了Subject接口 public class WeatherData implements Subject { // 我们加上一个ArrayList来记录观察者,此ArrayList是在构造器中建立的。 public ArrayList observers; //记录温度、湿度和气压 private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList(); } // 当注册观察者时,我们只要把它加到ArrayList的后面即可 @Override public void registerObserver(Observer o) { observers.add(o); } // 当观察者想取消注册,我们把它从ArrayList中删除即可 @Override public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { observers.remove(i); } } // 在这里,我们把状态告诉每一个观察者 // 因为观察者都实现了update(),所以我们知道如何通知它们 @Override public void notifyObservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = (Observer) observers.get(i); observer.update(temperature, humidity, pressure); } } // 当从气象站得到更新观测值时,我们通知观察者 public void measurementsChanged(){ notifyObservers(); } //当我们调用这个方法更新数据时,会自动通知所有观察者 public void setMeasurements(float temperature, float humidity, float pressure){ this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }3、定义观察者接口和其具体实现
public interface Observer { // 当气象观测值改变时,主题会把温度、湿度、气压的状态值当作方法的参数,传送给观察者 public void update(float temp, float humidity, float pressure); }操作方法的接口:
public interface DisplayElement { // 当布告板需要显示时,调用此方法 public void display(); }观察者的实现类:
// 此布告板实现了Observer接口,所以可以从WeatherData对象中获得改变 // 它也实现了DisplayElement接口,因为我们的API规定所有的布告板都必须实现此接口 public class CurrentConditionsDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject weatherData; // 构造器需要WeatherData对象(也就是主题)作为注册之用 public CurrentConditionsDisplay(Subject weatherData){ this.weatherData = weatherData; weatherData.registerObserver(this); } // display()方法就是把最近的温度和湿度显示出来 @Override public void display() { System.out.println("Cuttent conditions:" + temperature + "F degrees and " + humidity + "% humidity"); } // 当update()被调用时,我们把温度和湿度保存起来,然后调用display() @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; display(); } }4、编写测试方法
public class WeatherStation { public static void main(String[] args){ // 建立WeatherData对象 WeatherData weatherData = new WeatherData(); // 建立目前状况布告板 CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);//这一步完成了观察者的注册操作。 // 模拟新的气象测量 //每次调用weatherData的setMeasurements时,会遍历调用所有观察者的update方法。 weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); } }5、运行结果
Cuttent conditions: 80.0 F degrees and 65% humidity Cuttent conditions: 82.0 F degrees and 70% humidity Cuttent conditions: 78.0 F degrees and 90% humidity
三、JAVA提供的对观察者模式的支持
1、JAVA中的内置接口和类实现public interface Observer { void update(Observable o, Object arg); }Observable类:被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类非常重要:一个是setChanged(),另一个是notifyObservers()。第一方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己。
public class Observable { private boolean changed = false; private Vector obs; /** Construct an Observable with zero Observers. */ 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); } /** * 如果本对象有变化(那时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; } /** * Returns the number of observers of this <tt>Observable</tt> object. * * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); } }这个类代表一个被观察者对象,有时称之为主题对象。一个被观察者对象可以有数个观察者对象,每个观察者对象都是实现Observer接口的对象。在被观察者发生变化时,会调用Observable的notifyObservers()方法,此方法调用所有的具体观察者的update()方法,从而使所有的观察者都被通知更新自己。
public class Watched extends Observable{ private String data = ""; public String getData() { return data; } public void setData(String data) { if(!this.data.equals(data)){ this.data = data; setChanged(); } notifyObservers(); } }观察者类Watcher源代码
public class Watcher implements Observer{ public Watcher(Observable o){ o.addObserver(this); } @Override public void update(Observable o, Object arg) { System.out.println("状态发生改变:" + ((Watched)o).getData()); } }
public class Test { public static void main(String[] args) { //创建被观察者对象 Watched watched = new Watched(); //创建观察者对象,并将被观察者对象登记 Observer watcher = new Watcher(watched); //给被观察者状态赋值 watched.setData("start"); watched.setData("run"); watched.setData("stop"); } }