观察者模式是23种设计模式中常用的一种,定义的是一对多的依赖关系,一个被观察者(主题)多个观察者。当主题发生改变的时候,会主动通知所有在主题上注册过的观察者。也被称为发布-订阅模式。
它包含四种角色:
(1)抽象主题角色(Subject):抽象主题提供一个接口,包含增加、移除和通知观察者的方法。
(2)具体主题角色(ConcreteSubject):具体主题是被观察者所观察的对象,它包含主题所有的观察者列表,是抽象主题的具体实现。当主题状态发生改变时,主动通知观察者。
(3)抽象观察者(Watcher):是具体观察者的抽象接口,它包含更新观察者的方法。
(4)具体观察者(ConcreteWatcher):实现抽象观察者接口,实现提供更新其自身的方法。
在JDK中,抽象主题角色被定义为了一个类而不是接口,好处是不需要自己实现一些功能,当然坏处就是由于Java的单继承多实现的特性,不是很灵活。
下面是仿照JDK中的例子写的观察者模式
- 抽象主题(被观察对象)
public abstract class Subject {
private boolean changed = false;
private Vector obs;
public Subject() {
obs = new Vector();
}
public synchronized void addObserver(Observer ob) {
if (obs == null)
throw new NullPointerException();
if (!obs.contains(ob)) {
obs.add(ob);
}
}
public synchronized void deleteObserver(Observer ob) {
obs.remove(ob);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length - 1; i >= 0; i--) {
((Observer) arrLocal[i]).update(this, arg);
}
}
public synchronized void clearChanged() {
this.changed = false;
}
public synchronized void setChanged() {
this.changed = true;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
-
实际主题
public class WeatherData extends Subject{ private float temperature; public float getTemperature() { return temperature; } public void setTemperature(float temperature) { this.temperature = temperature; setChanged(); notifyObservers(); } } -
抽象观察者
public interface Observer { /** * 更新接口 * @param state 更新的状态 */ public void update(Subject s, Object arg); } -
具体观察者
public class WeatherDisplayer implements Observer{ public WeatherDisplayer(Subject sub) { sub.addObserver(this); } @Override public void update(Subject s, Object arg) { if (s instanceof WeatherData) System.out.println("the weather data has been changed to " +((WeatherData)s).getTemperature()); } public static void main(String[] args) { WeatherData wd = new WeatherData(); WeatherDisplayer wdis = new WeatherDisplayer(wd); wd.setTemperature(2.1f); } }
观察者模式个人的理解是将观察者注册在主题上,也就是主题会拿到观察者的引用的集合。
观察者模式的优点如下:
(1)它把观察者与被观察者分离,并将二者间的关系通过抽象观察者和抽象被观察者联系在一起,当一方发生变化时不会影响另一方的执行,从而降低了程序的耦合。
(2)可以支持多种不同的具体观察者实现,有利于程序的扩展。
(3)观察者的数目是可变的,主题可以实现动态的增加或移除观察者对象。
(4)被观察者在自身状态发生变化时,会主动通知观察者,如果不是被观察者主动通知,那就需要观察者通过定时任务的方式来监控被观察者的状态是否发生变化,被观察者主动通知的方式要比观察者定时监控方式性能更高。
观察者模式的缺点:
(1)观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理。但同时,这也算是观察者模式一个缺点,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。并且,在链式结构中,比较容易出现循环引用的错误,造成系统假死。
(2) 观察者模式由于是主题持有观察者对象的引用,所以很容易在观察者没有及时注销后造成内存泄漏,JVM没有及时GC未被使用的观察者