思想
观察者模式是使用的比较普遍的设计模式,其核心思想是在被观察者(Observable/Subject)中放入观察者(Observer)的实例列表,一旦被观察者有数据更新,则遍历观察者列表,调用观察者方法来更新数据。
下面举个例子:比如一家气象站有气象数据,拥有历史 当前和未来数天的天气数据,现在要将这些数据显示到天气布告板上去,但是,布告板有详细的布告板也有简单的布告板,总之,数据可能给布告板的都是相同,但是布告板可能显示成不同的样子,或者布告板只取它需要的数据显示。这个例子可以用观察者模式来实现。
天气站实现
DisplayElement.java
package observer; public interface DisplayElement { public void display(); //布告板显示 }
Observer.Java
package observer; public interface Observer { public void update(float temp,float humidity,float pressure); //状态改变时调用 }
CurrentCondtionsDisplay.Java
package subject; import java.util.ArrayList; import observer.DisplayElement; import observer.Observer; public class CurrentConditionsDisplay implements Observer,DisplayElement{ private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay( Subject weatherData) { //注册 // TODO Auto-generated constructor stub this.weatherData = weatherData; weatherData.resisterObserver(this); } @Override public void update(float temp, float humidity, float pressure) { // TODO Auto-generated method stub this.temperature = temperature; this.humidity = humidity; display(); } @Override public void display() { // TODO Auto-generated method stub System.out.println("temperature:" + temperature + " humidity:"+humidity); } }
Subject.Java
package subject; import observer.Observer; public interface Subject { public void resisterObserver(Observer o); //加入成为观察者 public void removeObserver(Observer o); //从观察者退出 public void notifyObserver(); //主题状态改变时方法调用,通知所有观察者 }
WeatherData.Java
package subject; import java.util.ArrayList; import observer.Observer; public class WeatherData implements Subject{ private ArrayList observers; private float temperature; private float humidity; private float pressure; public WeatherData() { // TODO Auto-generated constructor stub observers = new ArrayList(); } @Override public void resisterObserver(Observer o) { //加入 // TODO Auto-generated method stub observers.add(o); } @Override public void removeObserver(Observer o) { //删除 // TODO Auto-generated method stub int i = observers.indexOf(o); if(i >= 0) { observers.remove(i); } } @Override public void notifyObserver() { //对观察者一个一个跟新 // TODO Auto-generated method stub for(int i = 0;ii){ Observer observer = (Observer)observers.get(i); observer.update(temperature, humidity, pressure); } } public void measurementsChanged() { notifyObserver(); } public void setMeasurements(float temperature,float humidity,float pressure){ this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }
Test.Java
package test; import subject.CurrentConditionsDisplay; import subject.WeatherData; public class Test { public static void main(String[] args) { // TODO Auto-generated method stub WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80.0f, 69.0f, 30.4f); } }
结果
总结
JAVA API的观察者模式的实现虽然减少了不少代码,但是也存在诸多扩展和灵活性问题。如果JAVA API提供的方式已经够用,那么就可以使用简便的JAVA API方式,但是如果觉得程序后期需要扩展的可能性大,那么最好还是不要闲麻烦,自己实现一下。对比之前的总结,我觉得还是当前这个版本比较通俗易懂。
在Java和Android系统中,观察者模式的例子很常见,比如Swing组件和Android Button控件的点击事件监听。Android 的广播和广播接收者,也是利用注册和解除注册来实现接收广播的,至少形式上很相似。
这就像从报社订报纸,每个用户可以选择定或者不定报纸。报社每月会遍历订阅用户列表,给他们寄去报纸;如果用户中途取消订阅,报社就删除该用户,下次不再寄去报纸。其他没有订阅的用户如果感兴趣了,也可以订阅,报社会在列表加入该用户,下次寄去报纸给该用户。
适用场景
1.当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化
2.如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变
3.当一个对象必须通知其他的对象,但是你又希望这个对象和其他的被通知的对象是松散耦合的