0. 前言
观察者模式在许多地方都能够用到,特别是作为MVC模式的一部分,在MVC中,模型(M):存放数据,视图(V):显示数据。当模型中的数据发生改变时,视图会得到通知,这是典型的观察者模式。
1. 定义
观察者模式:定义了一对多的关系,一个对象作为主题,它维护了一系列的依赖对象,当主题的状态发生改变时,会自动地通知依赖对象(通常通过调用依赖对象的方法来实现)。
官方定义:wiki
2. 应用
这里通过《Head first 设计模式》中的例子来实现观察者模式。这里有一个气象数据和公布栏,当气象数据发生改变时,会通知公布栏,使其更新数据。
源码:
主题Subject接口:
1 package ObserverPattern; 2 3 public interface Subject { 4 public void registerObserver( Observer observer ); 5 public void removeObserver( Observer observer ); 6 public void notifyObservers(); 7 }
观察者Observer接口
1 package ObserverPattern; 2 3 public interface Observer { 4 public void update(Object obj); 5 }
气象数据实现:
1 package ObserverPattern; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 6 public class WeatherData implements Subject { 7 8 private ArrayList<Observer> observers = null; 9 private double temperature; 10 private double humidity; 11 private double pressure; 12 13 public WeatherData( ) 14 { 15 observers = new ArrayList<>(); 16 } 17 18 public double getTemperature() { 19 return temperature; 20 } 21 22 public double getHumidity() { 23 return humidity; 24 } 25 26 public double getPressure() { 27 return pressure; 28 } 29 30 public void SetWeather( double temperature, double humidity, double pressure ) 31 { 32 this.temperature = temperature; 33 this.humidity = humidity; 34 this.pressure = pressure; 35 mesurementsChanged(); 36 } 37 38 public void mesurementsChanged() 39 { 40 notifyObservers(); 41 } 42 43 @Override 44 public void registerObserver(Observer observer) { 45 observers.add(observer); 46 } 47 48 @Override 49 public void removeObserver(Observer observer) { 50 observers.remove(observer); 51 } 52 53 @Override 54 public void notifyObservers() { 55 56 for ( Iterator<Observer> iterator = observers.iterator(); iterator.hasNext(); ) { 57 Observer observer = (Observer) iterator.next(); 58 observer.update(this); 59 } 60 } 61 62 }
显示接口:
1 package ObserverPattern; 2 3 public interface DisplayBoard { 4 public void display(); 5 }
公布栏实现:
1 package ObserverPattern; 2 3 public class CurrentWeatherBoard implements Observer, DisplayBoard { 4 5 private double temperature; 6 7 public CurrentWeatherBoard( Subject subject ) { 8 subject.registerObserver(this); 9 } 10 11 @Override 12 public void update(Object obj) { 13 if ( obj instanceof WeatherData ) { 14 WeatherData weatherData = (WeatherData)obj; 15 this.temperature = weatherData.getTemperature(); 16 display(); 17 } 18 } 19 20 @Override 21 public void display() { 22 System.out.println(this.getClass().getName() + ":" + this.temperature); 23 } 24 25 }
3. JDK中Observable类分析
在JDK中提供了Observable类以及Observer接口方便实现观察者模式,但是这里的主题是Observable是一个类,需要通过继承来实现,所以很大的限制了它的使用。
Observable类的添加观察者方法,通过synchronized实现同步,其Observable内部维护着一个Vector容器,用于存放观察者对象。
1 public synchronized void addObserver(Observer o) { 2 if (o == null) 3 throw new NullPointerException(); 4 if (!obs.contains(o)) { 5 obs.addElement(o); 6 } 7 }
通知函数,这里会判断一个标识,所以在调用通知时需要先调用 setChanged 方法,然后将其观察者保存到一个数组中,这里会有一个问题,即当调用删除一个观察者的时候,如果正在调用notifyObservers时,依然会通知到被删除的观察者。对于添加来说也是一样的,会错过这一次的通知。
1 public void notifyObservers(Object arg) { 2 3 Object[] arrLocal; 4 5 synchronized (this) { 6 if (!changed) 7 return; 8 arrLocal = obs.toArray(); 9 clearChanged(); 10 } 11 12 for (int i = arrLocal.length-1; i>=0; i--) 13 ((Observer)arrLocal[i]).update(this, arg); 14 }