一、说明
观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知"监控"该对象的其他对象。
(一) 解决问题
主要解决一个对象的状态变化时,需要通知其他对象,并且这些被通知的对象可能是多个且不确定的。
(二) 使用场景
- 应用中的一些对象必须观察其他对象状态并进行操作时,如消息订阅、动态推送
- 当一个对象状态的改变需要改变其他对象,或实际对象是事先未知的或动态变化的时
二、结构
- **发布者(Publisher)**会向其他对象发送值得关注的事件。事件会在发布者自身状态改变或执行特定行为后发生。发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架。
- 当新事件发生时,发送者会遍历订阅列表并调用每个订阅者对象的通知方法。该方法是在订阅者接口中声明的。
- **订阅者(Subscriber)**接口声明了通知接口。在绝大多数情况下,该接口仅包含一个update更新方法。该方法可以拥有多个参数,使发布者能在更新时传递事件的详细信息。
- **具体订阅者(ConcreteSubscribers)**可以执行一些操作来回应发布者的通知。所有具体订阅者类都实现了同样的接口,因此发布者不需要与具体类相耦合。
- 订阅者通常需要一些上下文信息来正确地处理更新。因此,发布者通常会将一些上下文数据作为通知方法的参数进行传递。发布者也可将自身作为参数进行传递,使订阅者直接获取所需的数据。
- **客户端(Client)**会分别创建发布者和订阅者对象,然后为订阅者注册发布者更新。
三、伪代码
python
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
__doc__ = """
观察者模式
例:股票价格监控,当股票价格变化时,通知所有订阅者
"""
from abc import ABC, abstractmethod
from typing import List
class Subject(ABC):
"""发布者基类"""
@abstractmethod
def register_observer(self, observer):
pass
@abstractmethod
def remove_observer(self, observer):
pass
@abstractmethod
def notify_observers(self):
pass
class Observer(ABC):
"""订阅者基类"""
@abstractmethod
def update(self):
pass
class StockPriceSubject(Subject):
"""具体发布者"""
def __init__(self):
self._observers: List[Observer] = []
self._price = 0.0
def register_observer(self, observer):
self._observers.append(observer)
def remove_observer(self, observer):
self._observers.remove(observer)
def notify_observers(self):
for observer in self._observers:
observer.update()
def set_price(self, price):
self._price = price
self.notify_observers()
def get_price(self):
return self._price
class Investor(Observer):
"""具体订阅者"""
def __init__(self, name, subject):
self._name = name
self._subject = subject
def update(self):
price = self._subject.get_price()
print(f"{self._name} 收到新价格: {price}")
if __name__ == "__main__":
"""
张三 收到新价格: 100.0
李四 收到新价格: 100.0
------------------------------
张三 收到新价格: 110.0
"""
stock_subject = StockPriceSubject()
investor1 = Investor("张三", stock_subject)
investor2 = Investor("李四", stock_subject)
stock_subject.register_observer(investor1)
stock_subject.register_observer(investor2)
# 股票变动自动通知订阅者
stock_subject.set_price(100.0)
print("-" * 30)
# 李四取消订阅订阅
stock_subject.remove_observer(investor2)
stock_subject.set_price(110.0)
四、优缺点
优点
- **开闭原则:**可以在不修改主题和观察者类的情况下增加新的观察者
- **主题和观察者之间是松耦合的:**主题对象不需要知道观察者的具体实现,只需要知道观察者接口即可。这样可以降低对象之间的耦合度,使得系统更加灵活。
缺点
- 如果观察者很多,通知所有观察者可能会导致性能问题。
- 如果观察者和主题之间有循环依赖,可能会导致系统复杂性增加。