观察者模式,也被称为发布订阅模式,还有的人叫它"监听器模式",它是设计模式中行为型模式的一种,近些年开始流行的响应式编程(WebFlux)就是观察者模式的应用之一。
观察者模式的核心思想就是当被观察者(Observable)的状态发生了改变(某一个对象被修改 / 做出某些反应 / 发布一个信息等),会逐一通知监听着这个对象的观察者(Observer)。
观察者 观察 被观察者这个行为称为订阅(subscribe)或 注册(register),被观察者通知观察者,观察者的做出的应对称为响应(update)。
举个栗子:我看电视,我即观察者,电视就是被观察者,我看电视这个行为称为订阅,电视上放了一段马老师的传统功夫,我立马把电视砸了,这个行为即是响应。这就是简单的一对一的观察者模式。
实际情况是,一个节目出来,世界各地肯定不止一个人在看,所以一个被观察者可以有很多观察者,观察者模式也主要是处理一种 一对多的依赖关系。
观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
现在我们定义一个观察者接口
public interface Observer {
void update(String event);
}
update方法用于对事件做出响应
一个被观察者父类
public class Observable {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
//通知所有订阅者 执行响应
public void notifyObservers(String event) {
for (Observer observer : observers) {
observer.update(event);
}
}
}
用一个list维护观察者列表,addObserver添加观察者, removeObserver移除观察者,notifyObservers取出所有订阅的观察者,逐一通知其更新
现在定义一个电视节目类,继承被观察者父类
public class Television extends Observable{
public void play(String event) {
System.out.println("电视正在播放"+ event);
notifyObservers(event);
}
}
play方法是电视节目类的行为,并在执行该行为时通知所有订阅者,即看电视的人
定义一个人类观察员,实现观察者接口
public class ManObserver implements Observer{
@Override
public void update(String event) {
System.out.println("收到消息,有新的电视剧上线:"+ event);
}
}
覆写观察者响应方法,打印一条数据
测试方法:
public static void main(String[] args) throws Exception {
Television television = new Television();
Observer zhangSan = new ManObserver();
Observer liSi = new ManObserver();
Observer wanWu = new ManObserver();
television.addObserver(zhangSan);
television.addObserver(liSi);
television.addObserver(wanWu);
television.play("回村的诱惑");
}
新建一个电视对象,添加三个人类观察员:张三、李四、王五,这哥仨正躺在床上看电视。
打印如下:
电视正在播放回村的诱惑
收到消息,有新的电视剧上线:回村的诱惑
收到消息,有新的电视剧上线:回村的诱惑
收到消息,有新的电视剧上线:回村的诱惑
三人都收到了消息
当某一个订阅者不需要继续观察时,执行removeObserver()移除该观察者对象即可
在SpringFramework设计中也使用了观察者模式,他们就是事件机制和监听器。监听器充当订阅者,监听特定的事件;事件源充当被观察的主题,用来发布事件;IOC 容器本身也是事件广播器,可以理解成观察者。
同样的,java源码中已经有了观察者和被观察者的实现,我们无需自己定义:
java.util.Observer 类:
public interface Observer {
void update(Observable o, Object arg);
}
响应方法的入参改为了范围更广的Object类型,同时把被观察者对象也传了进来
java.util.Observable 类:
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(java.util.Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(java.util.Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!hasChanged())
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length - 1; i >= 0; i--)
((Observer) arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
注意changed相关方法和notifyObservers,只有调用了setChanged()方法使changed为true的时候才会通知订阅者,被观察者也不是以list维护订阅者列表,而是Vector,同时添加了synchronized关键字保证线程安全。