《Head Frist 设计模式》学习笔记——观察者模式
1.主题+观察者=观察者模式
2.观察者模式定义
观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
3.定义观察者模式
优点:
- 观察者模式提供了一种对象设计,让主题和观察者之间松耦合。
- 主题只知道观察者实现了某个接口,不需要知道观察者的具体类是谁、做了哪些操作。
- 任何时候我们都可以增加新的观察者,或删除已有的观察者。
- 有新的观察者时,主题的代码不需要修改。主题只负责发送通知给所有实现了观察者接口的对象。
4.示例(书中是以一个气象站的实现作为示例)
Subject
public interface Subject{ public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); } public interface Observer{ public void update(float temp); } public interface DisplayElement{ public void display(); }
WeatherData
public class WeathData implements Subject{ private ArrayList observers; private float temp; 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(temp); } } public void measurementsChanged(){ notifyObservers(); } public void setMeasurements(float temp){ this.temp = temp; measurementsChanged(); } //WeatherData的其他方法 }
CurrentConditionsDisplay
public class CurrentConditionsDisplay implements Observer,DisplayElement{ private float temp; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData){ this.weatherData = weaterhData; weatherData.registerObserver(this); } public void update(float temp){ this.temp = temp; display(); } public void display(){ System.out.println("Current conditions: " + temp); } }
测试程序
WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80);
实现过程
5.Java中内置的观察者模式
Java API有内置的观察者模式,java.util包(package)内包含最基本的Observer接口(与我们自己定义的Subject接口类似)与Observable类
- Observer接口
/**
* {@code Observer} is the interface to be implemented by objects that
* receive notification of updates on an {@code Observable} object.
*
* @see Observable
*/
public interface Observer {
/**
* This method is called if the specified {@code Observable} object's
* {@code notifyObservers} method is called (because the {@code Observable}
* object has been updated.
*
* @param observable
* the {@link Observable} object.
* @param data
* the data passed to {@link Observable#notifyObservers(Object)}.
*/
void update(Observable observable, Object data);
}
Observable类
/** * Observable is used to notify a group of Observer objects when a change * occurs. On creation, the set of observers is empty. After a change occurred, * the application can call the {@link #notifyObservers()} method. This will * cause the invocation of the {@code update()} method of all registered * Observers. The order of invocation is not specified. This implementation will * call the Observers in the order they registered. Subclasses are completely * free in what order they call the update methods. * * @see Observer */ public class Observable { List<Observer> observers = new ArrayList<Observer>(); boolean changed = false; /** * Constructs a new {@code Observable} object. */ public Observable() { } /** * Adds the specified observer to the list of observers. If it is already * registered, it is not added a second time. * * @param observer * the Observer to add. */ public void addObserver(Observer observer) { if (observer == null) { throw new NullPointerException("observer == null"); } synchronized (this) { if (!observers.contains(observer)) observers.add(observer); } } /** * Clears the changed flag for this {@code Observable}. After calling * {@code clearChanged()}, {@code hasChanged()} will return {@code false}. */ protected void clearChanged() { changed = false; } /** * Returns the number of observers registered to this {@code Observable}. * * @return the number of observers. */ public int countObservers() { return observers.size(); } /** * Removes the specified observer from the list of observers. Passing null * won't do anything. * * @param observer * the observer to remove. */ public synchronized void deleteObserver(Observer observer) { observers.remove(observer); } /** * Removes all observers from the list of observers. */ public synchronized void deleteObservers() { observers.clear(); } /** * Returns the changed flag for this {@code Observable}. * * @return {@code true} when the changed flag for this {@code Observable} is * set, {@code false} otherwise. */ public boolean hasChanged() { return changed; } /** * If {@code hasChanged()} returns {@code true}, calls the {@code update()} * method for every observer in the list of observers using null as the * argument. Afterwards, calls {@code clearChanged()}. * <p> * Equivalent to calling {@code notifyObservers(null)}. */ public void notifyObservers() { notifyObservers(null); } /** * If {@code hasChanged()} returns {@code true}, calls the {@code update()} * method for every Observer in the list of observers using the specified * argument. Afterwards calls {@code clearChanged()}. * * @param data * the argument passed to {@code update()}. */ @SuppressWarnings("unchecked") public void notifyObservers(Object data) { int size = 0; Observer[] arrays = null; synchronized (this) { if (hasChanged()) { clearChanged(); size = observers.size(); arrays = new Observer[size]; observers.toArray(arrays); } } if (arrays != null) { for (Observer observer : arrays) { observer.update(this, data); } } } /** * Sets the changed flag for this {@code Observable}. After calling * {@code setChanged()}, {@code hasChanged()} will return {@code true}. */ protected void setChanged() { changed = true; } }
使用方法
注册和解注册观察者
- 实现观察者接口(java.util.Observer)
- 调用addObserver()方法成为观察者
- 调用deleteObserver()方法解注册观察者
发送通知
- 继承java.util.Observable生成“被观察者”类
调用setChanged()方法
用来标记状态已经改变的事实,调用notifyObservers()方法之前必须先调用setChanged(),否则观察者不会被通知 setChanged(){ changed = true; } notifyObservers(Object arg){ if(changed){ for every observer on the list{ call update(this,arg); } changed = false; } } notifyObservers(){ notifyObservers(null); }
调用notifyObservers()或notifyObservers(Object arg)
notifyObservers()会调用notifyObservers(Object arg)
public void notifyObservers() { notifyObservers(null); }