观察者模式(Observer Design Pattern),也被称为发布订阅模式(Publish-Subscribe Design Pattern),它适用于当对象间存在一对多的依赖关系;当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并更新自身。
在观察者模式中,被依赖的对象被称为被观察者,所以依赖于它的对象被称为观察者,一般来说,同一种观察中,只能有一个被观察者,以及若干个观察者。
实际上,观察者模式是一个比较抽象的模式,根据不同的应用场景和需求,有完全不同的实现方式,也有非常多叫法,比如:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener。不管怎么称呼,只要应用场景符合刚刚给出的定义,都可以看作观察者模式。
优缺点
优点
- 观察者和被观察者是抽象耦合的。
- 基于抽象接口编程,定义观察者非常方便。
- 观察者功能单一,符合单一职责原则。
缺点
- 解耦后,可读性变弱,需要理解模式本身才能更好理解代码。
- 如果观察者很多,将所有的观察者都通知到会花费很多时间,尤其在同步阻塞的情况下。
应用场景
观察者模式可以说是一个应用场景非常广泛的设计模式,比如,邮件订阅、RSS Feeds,计算机的广播通信,都是观察者模式。本质上来说,只要符合观察者模式定义的对象之间一对多的依赖关系,都可以是观察者模式。
观察者模式的构成
观察者模式的构成并不复杂,主要就是需要定义好解耦后,观察者与被观察者之间的交互方式,据此可以划为以下四类:
- 观察者抽象类 :定义观察者需要实现的接口规范。
- 被观察者抽象类 :定义被观察者需要实现的接口规范。
- 具体的观察者类 :继承观察者抽象类,并实现逻辑。
- 具体的被观察者类: 继承被观察者抽象类,并实现逻辑。
通过一个消息推送的例子来说明。
当我们希望某个消息推送给一批人,并且可以不断的添加或减少要推送的特定群体。
背后做的事情,就是维护一个推送列表,也即是观察者,当有新消息时,推送给列表中的所有群体。
观察者抽象类
class Observer:
@abstractmethod
def update(self):
"""观察者自己的方法"""
pass
定义了观察者需要实现 update 方法,在被通知后需要执行。
被观察者抽象类
class Subject:
def __init__(self):
self.observer_list = []
@abstractmethod
def addObserver(self, observer: Observer):
"""添加一个观察者"""
pass
@abstractmethod
def removeObserver(self, observer: Observer):
"""移除一个观察者"""
pass
@abstractmethod
def notify(self):
"""通知所有观察者"""
pass
定义了被观察者的规范,需要实现添加、删除观察者,以及通知所有观察者的方法。
具体的被观察者类
class ConcreteSubject(Subject):
def addObserver(self, observer: Observer):
self.observer_list.append(observer)
def removeObserver(self, observer: Observer):
self.observer_list.remove(observer)
def notify(self):
[i.update() for i in self.observer_list]
具体的观察者类
class ConcreteObserver1(Observer):
def update(self):
print("ConcreteObserver1 的 update 方法")
class ConcreteObserver2(Observer):
def update(self):
print("ConcreteObserver2 的 update 方法")
不同的具体观察者,实现的 update 方法不尽相同。
具体使用
# 创建一个主题,也就是被观察者
subject = ConcreteSubject()
# 添加两个观察者
observer1, observer2 = ConcreteObserver1(), ConcreteObserver2()
subject.addObserver(observer1)
subject.addObserver(observer2)
# 通知观察者
subject.notify()
# ===== 输出 =====
ConcreteObserver1 的 update 方法
ConcreteObserver2 的 update 方法
总结
观察者模式在现实中的应用场景是非常广泛的,并且有非常多成熟的应用。可以同步阻塞实现,也可以异步非阻塞实现,可以是进程内,也可以是跨进程方式,不同的实现方式,具体的实现也不一样,但是底层的设计思想是一致的。
所以这也告诉我们,掌握基本的基础知识和指导思想,怎么扩展,都是在这些基础上添砖加瓦,万变不离其宗,学好基础很重要。