定义
- 在对象间定义一种一对多的依赖关系,当这个对象状态发生改变时,所有依赖它的对象都会被通知并自动更新。
监听模式的模型抽象
代码框架
from abc import ABCMeta, abstractmethod
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法
class Observer(metaclass=ABCMeta):
"""观察者的基类"""
@abstractmethod
def update(self, observable, object):
pass
class Observable:
"""被观察者的基类"""
def __init__(self):
self.__observers = []
def addObserver(self, observer):
self.__observers.append(observer)
def removeObserver(self, observer):
self.__observers.remove(observer)
def notifyObservers(self, object=0):
for o in self.__observers:
o.update(self, object)
类图
基于框架的实现
class WaterHeater(Observable):
"""热水器:战胜寒冬的有利武器"""
def __init__(self):
super().__init__()
self.__temperature = 25
def getTemperature(self):
return self.__temperature
def setTemperature(self, temperature):
self.__temperature = temperature
print("当前温度是:" + str(self.__temperature) + "℃")
self.notifyObservers()
class WashingMode(Observer):
"""该模式用于洗澡用"""
def update(self, observable, object):
if isinstance(observable, WaterHeater) \
and observable.getTemperature() >= 50 and observable.getTemperature() < 70:
print("水已烧好!温度正好,可以用来洗澡了。")
class DrinkingMode(Observer):
"该模式用于饮用"
def update(self, observable, object):
if isinstance(observable, WaterHeater) and observable.getTemperature() >= 100:
print("水已烧开!可以用来饮用了。")
def testWaterHeater():
heater = WaterHeater()
washingObser = WashingMode()
drinkingObser = DrinkingMode()
heater.addObserver(washingObser)
heater.addObserver(drinkingObser)
heater.setTemperature(40)
heater.setTemperature(60)
heater.setTemperature(100)
testWaterHeater()
模型说明
- 设计要点
- 要明确谁是观察者谁是被观察者
- Observable在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否订阅Subject的通知。
- 被观察者至少需要有三个方法:添加监听者、移除监听者、通知Observer的方法。
- 观察者至少要有一个方法:更新方法,即更新当前的内容,做出相应的处理。
- 添加监听者和移除监听者在不同的模型称谓中可能会有不同命名,如:
- 在观察者模型中一般是
addObserver
/removeObserver
;
- 在源/监听器(Source/Listener)模型中一般是
attach
/detach
- 应用在桌面编程的窗口中还可能是
attachWindow
/detachWindow
或Register
/UnRegister
- 推模型和拉模型
- 推模型
- 被观察者对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
- 一般在这种模型的实现中,会把被观察者对象中的全部或部分信息通过update参数传递给观察者(
update(Object obj)
,通过obj
参数传递)。
- 拉模型
- 被观察者在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到被观察者对象中获取,相当于观察者从被观察者对象中拉数据。
- 一般在这种模型的实现中,会把被观察者对象自身通过update方法传递给观察者(
update(Observable observable)
,通过observable
参数传递),这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。
应用场景
- 对一个对象状态或数据的更新需要其他对象同步更新,或者一个对象的更新需要依赖另一个对象的更新。
- 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节,如消息推送。