观察者模式,就像订报纸杂志。出版社(主题Subject)有新的报纸出版就会通知读者(观察者 Observer),当读者不想看报纸的时候,取消订阅就不会再受到新送来的报纸。这就是一种典型的观察者模式。
观察者模式:在对象之间定义一对多的依赖,这样当一个对象改变状态,依赖它的对象都会受到通知并自动更新。
观察者类图:
Subject是主题接口,对象使用这个接口注册为观察者也可以把自己从观察者中删除。ConcreteSubject是实现主题的接口,除了注册和撤销方法之外还有notifyOvservers(),用于在状态改变是更新当前所有的观察者。
Observer观察者接口,这个接口只有update()一个方法,当主题状态改变时它被调用。
观察者模式提供了一种对象设计,让主题和观察者之间松耦合。对于主题和观察者之间唯一依赖的东西就是实现Observer接口的对象列表,可以随时增删观察者。
举个例子:气象观测版。一个WeatherData对象有关于温度、湿度、气压等方面的信息,将信息发送给布告板,布告板有很多种。下面就是这个例子的类图,为布告板建立一个共同的接口。
代码:
首先建立三个接口:
1 package com.Subject; 2 3 import com.Observer.Observer; 4 5 public interface Subject { 6 public void registerObserver(Observer o); 7 public void removeObserver(Observer o); 8 //当主题状态改变时,这个方法会被调用,以通知所有的观察者 9 public void notifyObservers(); 10 11 } 12 13 package com.Observer; 14 15 public interface Observer { 16 //所有的观察者都需要实现update的方法 17 //当气象观测值发生改变的时候,主题会把这些值作为参数传给观察者 18 public void update(float temp,float humidity,float pressure); 19 } 20 21 package com.Display; 22 23 public interface DisplayElement { 24 //DisplayElement接口只包含一个display方法。当广告版需要显示时调用此方法 25 public void display(); 26 27 }
WeatherData实现主题的接口
1 package com.Subject; 2 3 import java.util.ArrayList; 4 5 import com.Observer.Observer; 6 7 public class WeatherData implements Subject{ 8 private ArrayList observers;//这个就是观察者的列表 9 private float temperature; 10 private float humidity; 11 private float pressure; 12 13 public WeatherData(){ 14 observers=new ArrayList();//观察者的list在构造函数中建立 15 } 16 17 public void registerObserver(Observer o) { 18 observers.add(o);//注册就是把观察者加到列表中 19 20 } 21 22 public void removeObserver(Observer o) { 23 int i=observers.indexOf(o); 24 if(i>=0){ 25 observers.remove(i); 26 } 27 } 28 29 @Override 30 public void notifyObservers() { 31 //把状态告诉每一个观察者去更新数据 32 for(int i=0;i<observers.size();i++){ 33 Observer observer=(Observer) observers.get(i); 34 observer.update(temperature, humidity, pressure); 35 } 36 } 37 38 public void measurementsChanged(){ 39 //当从外界比如气象站得到更新观测值是,通知观察者 40 notifyObservers(); 41 } 42 public void setMeasurements(float temperature,float humidity,float pressure){ 43 this.humidity=humidity; 44 this.pressure=pressure; 45 this.temperature=temperature; 46 measurementsChanged(); 47 } 48 }
布告板:
1 package com.Display; 2 3 import com.Observer.Observer; 4 import com.Subject.Subject; 5 6 public class CurrentConditionsDisplay implements Observer,DisplayElement{ 7 private float temperature; 8 private float humidity; 9 private Subject weatherData; 10 11 12 public CurrentConditionsDisplay(Subject weatherData) { 13 //在构造器时注册observer 14 this.weatherData = weatherData; 15 weatherData.registerObserver(this); 16 } 17 18 @Override 19 public void display() { 20 System.out.println("Current conditions:"+temperature+"F degree and"+humidity+"% humidity"); 21 22 } 23 24 @Override 25 public void update(float temp, float humidity, float pressure) { 26 this.temperature=temp; 27 this.humidity=humidity; 28 display(); 29 } 30 31 }
测试:
package com.test; import com.Display.CurrentConditionsDisplay; import com.Subject.WeatherData; public class WeatherStation { public static void main(String args[]){ //首先建立一个WeahterData对象(主题) WeatherData weatherdata=new WeatherData(); //一个现实版 CurrentConditionsDisplay currentDisplay=new CurrentConditionsDisplay(weatherdata); //调用setMeasurements方法设立现在的weather值 weatherdata.setMeasurements(80, 65, 30.4f); } }
这样一个观察者模式,就做好了!
需要注意的是,在java.util包中包含了Observer包,然后任何observable对象的addOvserver()方法,不想当观察者时,调用deleteObserver()方法就可以了。但是最好自己写观察者,因为java API的Observable是一个类,必须要设计一个类继承它。如果某个类想同时具有Observable类和另一个超类的行为,就没有办法了(因为java不支持多重继承)