一、观察者模式的定义与特点
1、定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新
注:简单地说,主题 + 观察者 = 观察者模式 或者 出版者 + 订阅者 = 观察者模式
2、优点:
- 松耦合设计,降低了对象之间的依赖;
- 目标与观察者之间建立了一套触发机制。
3、缺点:
- 虽然是松耦合设计,但是并没有完全解除目标与观察者之间的依赖关系,导致有可能出现循环引用,系统崩溃;
- 当观察者很多时,通知会花费很多时间,影响程序的效率。
二、观察者模式满足的OO设计原则
1、主题与观察者之间的松耦合设计。所谓松耦合,即对象之间的互相依赖降到了最低,对象之间可以交互,但是不太清楚彼此的细节。
注:有多个观察者时,不可以依赖特定的通知次序
三、模式的结构
1、抽象主题:它提供了一个用于保存观察者对象的句积累和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
2、具体主题:它实现抽象主题中的通知方法,当具体主题的内部状态发生改变时,通知所有注册股的观察者对象。
3、抽象观察者:它是一个抽象类或者接口,包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
4、具体观察者:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自己的状态。
四、模式的应用场景
1、对象之间存在一对多关系,一个对象的状态发生改变会影响其他对象。
2、当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
五、具体实现(完整代码保存在github上):
//1、抽象主题 public interface Subject{ public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } //2、具体主题:WeatherData实现了抽象主题类Subject,注释部分是这样实现的;这里我们主要利用内置的支持来实现代码,因此需要调包import java.util.Observable //public class WeatherData implements Subject{ public class WeatherData extends Observable{ //private ArrayList observers; private float temperature; private float humidity; private float pressure; public WeatherData(){ //observers = new ArrayList(); } /*public void registerObserver(Observer o){ observers.add(o); } public void removeObserver(Observer o){ int i = observers.indexOf(o); if(i >= 0){ observers.remove(i); } } 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(){ setChanged(); notifyObservers(); } public void setMeasurements(float temperature,float humidity,float pressure){ this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } public float getTemperature(){ return this.temperature; } public float gethumidity(){ return this.humidity; } public float getPressure(){ return this.pressure; } } //3、抽象观察者 public interface Observer{ public void update(float temp,float humidity,float pressure); } //4、具体观察者 //(1)目前状况布告板观察者 public class CurrentConditionsDisplay implements Observer,DisplayElement{ Observable observable; private float temperature; private float humidity; public CurrentConditionsDisplay(Observable observable){ this.observable = observable; observable.addObserver(this); } public void update(Observable obs,Object arg){ if (obs instanceof WeatherData){ WeatherData weatherData = (WeatherData)obs; this.temperature = weatherData.getTemperature(); this.humidity = weatherData.gethumidity(); display(); } } public void display(){ System.out.println("Current conditions:" + temperature + "F degrees and " + humidity + "% humidity"); } } //(2)天气预报布告板观察者 public class ForecastDisplay implements Observer,DisplayElement{ private float currentPressure = 29.92f; private float lastPressure; public ForecastDisplay(Observable observable){ observable.addObserver(this); } public void update(Observable observable,Object arg){ WeatherData weatherData = (WeatherData)observable; if(observable instanceof WeatherData){ lastPressure = currentPressure; currentPressure = weatherData.getPressure(); display(); } } public void display(){ System.out.println("Last pressures:" + lastPressure + " and currentPressure:" + currentPressure); } } 5、进行测试 public class WeatherStation{ public static void main(String[] args){ WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); currentDisplay.display(); forecastDisplay.display(); } }
结果显示如下:
参考资料
[1] http://c.biancheng.net/view/1390.html
[2] head first 设计模式