今天的博客主题
设计模式 ——》 设计模式之观察者模式
观察者模式 OP (Observer Pattern)
定义
定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖者都会收到通知并更新。
其核心是将观察者与被观察者解耦,以类似于消息广播发送机制联动两者,使被观察者的变动能通知感兴趣的观察者们,从而做出响应。
观察者模式也被称为:发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
应用场景
1)当更改一个对象的状态可能需要更改其他对象,并且实际的对象集事先未知或动态更改时。
2)实现类似广播机制,无需知道具体接收者,只需要发送广播,感兴趣的对象自动接收广播
3)
生活中的场景也很多,比如闹钟的设置,APP角标通知,邮件通知,广播通知,桌面程序的事件响应
优点
1)符合开闭原则
2)可在运行时建立对象之间的关系
3)实现了一对多的通讯机制,支持事件注册机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者接收到通知。
4)
缺点
1)观察者数量过多,事件通知耗时比较长。
2)事件通知呈线性,如果其中一个观察者事件处理失败,则影响后续的观察者接收事件。
3)如果观察者和被观察者之间存在循环依赖,则可能造成两者之间循环调用,导致系统崩溃。
4)
源码中的应用
JDK API:
java.util.Observable
Spring Api:
org.springframework.context.ApplicationListener
代码示例
观察者模式主要包含四种角色
目标/主题(Subject):也就是被观察的对象,定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,提供了增加/删除/通知观察者对象的方法。,可以是接口或抽象类,也可以是一个具体类。
具体目标/主题(ConcreteSubject):目标/主题的子类,包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知。同时还实现了在目标/主题类中定义的抽象业务逻辑方法(若有),如果不需要扩展目标类,该类可省略。(其主要就是一个具体被观察者,当状态发生变化时,会通知观察者对象)
抽象观察者(Observer):观察者将对观察目标的改变做出反应,定义了响应通知的更新方法。
具体观察者(ConcreteObserver):维护一个指向具体目标对象的引用,存储具体观察者的有关状态,这些状态要和具体目标的状态保持一致。实现了抽象观察者的更新方法。(就是得到状态改变的通知,自动做出响应)
按照所包含的角色,写出的观察者代码可能会是这样的
// 目标、主题类
abstract class Subject{
// 定义一个观察者集合用于存储所有观察者对象
protected ArrayList<Observer> Observers = new ArrayList<>();
// 注册方法,往观察者集合增加一个观察者者
public void addObserver(Observer observer){
Observers.add(observer);
}
// 注销方法,在观察者集合删除一个观察者者
public void removeObserver(Observer observer){
Observers.remove(observer);
}
// 抽象方法,通知观察者
public abstract void notifys();
}
// 具体目标类
class ConcreteSubject extends Subject{
// 实现通知方法
@Override
public void notifys() {
// 遍历观察者集合,调用每一个观察者的响应方法
for (Object obs : Observers){
((Observer) obs).update();
}
}
}
// 抽象观察者
interface Observer{
void update();
}
// 具体观察者1
class ConcreteObserver1 implements Observer{
@Override
public void update() {
System.out.println("ConcreteObserver1 做出具体响应");
}
}
// 具体观察者2
class ConcreteObserver2 implements Observer{
@Override
public void update() {
System.out.println("ConcreteObserver2 做出具体响应");
}
}
// 客户端调用
public class ObserverPattern {
public static void main(String[] args) {
// 定义主题目标
Subject subject = new ConcreteSubject();
// 定义观察者
Observer o1 = new ConcreteObserver1();
Observer o2 = new ConcreteObserver1();
// 注册观察者
subject.addObserver(o1);
subject.addObserver(o2);
subject.notifys();
}
}
// 输出结果
ConcreteObserver1 做出具体响应
ConcreteObserver2 做出具体响应
但真正实现起来不用这么复杂,JDK为我们提供了API,还有Guava API 都能帮助我们轻松实现。