1.概念
观察者模式是一种行为设计模式,当一个对象的状态发生改变,所有依赖它的对象都能收到通知触发更新操作。
核心角色是被观察者Subject和观察者Observer。
2.JDK观察者模式
2.1.JDK观察者模式
JDK定义Observable、Observer类实现了观察者模式。
// 增删观察者列表
public synchronized void addObserver(Observer o) { }
public synchronized void deleteObserver(Observer o) { }
// 状态变更
protected synchronized void setChanged() { changed = true; }
protected synchronized void clearChanged() { changed = false; }
推拉模式
// 被观察者通过notifyObservers将数据推给观察者
notifyObservers(messageChargeResult);
// 观察者通过update拉取被观察者和数据
public void update(Observable o, Object arg) {
}
2.2.业务场景及使用
当被观察者的事件发生改变时,依赖它的不同运营商类型都需要接收到信息并进行处理。
// 充电结果作为被观察者
ChargeResultSubject subject = new ChargeResultSubject();
// 不同运营商观察者(重写update方法实现自定义处理逻辑)
StandardObserver standardObserver = new StandardObserver();
SpecialObserver specialObserver = new SpecialObserver();
// 添加观察者
subject.addObserver(standardObserver);
subject.addObserver(specialObserver);
// push的逻辑是设置状态变更并通知给观察者
subject.push(messageChargeResult);
2.3.JDK观察者模式缺陷
单继承限制。
线程安全问题,update方法没有加锁,会出现观察者列表的增删操作与update操作并发执行造成状态不一致。
设计冗余,必须调用setChanged()方法才触发通知。
3.Spring事件机制
3.1.spring事件发布/订阅机制
Spring框架中可以借助事件发布/订阅实现解耦,实现跟观察者模式相同的效果。
// 自定义温度事件
public class TemperatureEvent extends ApplicationEvent {
public TemperatureEvent(Object source, int temp) {
super(source);
this.temp = temp;
}
private final int temp;
}
// 发布事件
@Autowired
private ApplicationEventPublisher publisher;
public void setTemperature(int temp) {
publisher.publishEvent(new TemperatureEvent(this, temp));
}
// 监听事件
@EventListener
public void handleTemperature(TemperatureEvent event) {
System.out.println("温度更新:" + event.getTemp());
}
3.2.特点
Spring管理监听器的数据结构是CopyOnWriteArrayLsit,保证了新增和删除的安全性。
如果spring事件是同步发布的,那么发布和订阅是用同一个线程。对于共享的变量,需要使用锁或者原子类保障线程安全。
4.观察者模式的优点
每个观察者专注于单一职责。
支持广播通信,所有观察者自动接收通知。
动态管理观察者,符合开闭原则。