一、什么是监听模式?
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
监听模式又名观察者模式,是一种一对多的关系,被观察者(Observable,也称subject)对象在状态或内容发生变化时,会通知所有的观察者(observer)对象,使他们能够做出相应的变化。
观察者模式是对象的行为模式,又叫发布/订阅(Publish/Subscribe)模式、模型/视图(Model/View)模式、源/监听器(Source/Listener)模式或从属者(Dependents)模式。监听模式的核心思想就是在被观察者与观察者之间建立一种自动触发的关系。
二、代码框架
from abc import ABCMeta, abstractmethod # 引入ABCmeta和abstractmethod来定义抽象类和抽象方法。
class Observer(metaclass=ABCMeta):
'''观察者的基类'''
@abstractmethod
def update(self, observable, object):
pass
class Observable:
'''被观察者的基类'''
def __init__(self) -> None:
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)
三、代码示例
'''
@time: 2023/5/4 11:20
@autor: zyh
@file: observer.py
'''
from abc import ABCMeta, abstractmethod # 引入ABCmeta和abstractmethod来定义抽象类和抽象方法。
class WaterHeater:
'''热水器'''
def __init__(self) -> None:
self._observers = []
self._temperature = 25
def getTemperature(self):
return self._temperature
def setTemperature(self, temperature):
self._temperature = temperature
print("当前温度是:" + str(self._temperature) + "°C")
self.notifies()
def addObserver(self, observer):
self._observers.append(observer)
def notifies(self):
for o in self._observers:
o.update(self)
class WashingMode(Observer):
'''洗澡模式'''
def update(self, waterHeater):
if waterHeater.getTemperature() >= 50 and waterHeater.getTemperature() <=70:
print("水已烧好!温度正好,可以用来洗澡了。")
class DrinkingMode(Observer):
'''饮用模式'''
def update(self, waterHeater):
if waterHeater.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)
if __name__ == '__main__':
testWaterHeater()
输出:
当前温度是:40°C
当前温度是:60°C
水已烧好!温度正好,可以用来洗澡了。
当前温度是:100°C
水已烧开!可以用来饮用了。
from abc import ABCMeta, abstractmethod # 引入ABCmeta和abstractmethod来定义抽象类和抽象方法。
class Observer(metaclass=ABCMeta):
'''观察者的基类'''
@abstractmethod
def update(self, observable, object):
pass
class Observable:
'''被观察者的基类'''
def __init__(self) -> None:
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) -> None:
super().__init__()
self._temperature = 25
def getTemperature(self):
return self._temperature
def setTemperature(self, temperature):
self._temperature = temperature
print("当前温度是:" + str(self._temperature) + "°C")
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)
if __name__ == '__main__':
testWaterHeater()
输出:
当前温度是:40°C
当前温度是:60°C
水已烧好!温度正好,可以用来洗澡了。
当前温度是:100°C
水已烧开!可以用来饮用了。
补充说明
1. 设计要点
- 明确观察者与被观察者。
- Observable在发送广播通知时,无须指定具体的Observer,Observer可以自己决定是否订阅Subject的通知。
- 被观察者至少需要三个方法:添加监听者、移除监听者、通知监听者;观察者至少有一个方法:更新方法。
2. 推模型&拉模型
监听模式根据侧重功能可分为推模型和拉模型。
推模型:
被观察者向监听者推送信息,不管监听者是否需要。一般在这种模型的实现中,会把被观察者对象中的全部或部分信息通过update参数传递给观察者。
如某APP的服务要在凌晨1:00开始维护,所有服务暂停1小时,此时就需要向所有APP客户端推送完成的通知消息“本APP于凌晨1:00-2:00维护,期间所有服务暂停!”
即不管用户想不想知道,也不管用户会不会在此期间使用,消息都需要被准确无误的送达。
拉模型:
被观察者在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到被观察者对象中获取,相当于观察者从被观察者对象中拉数据。一般在这种模型的实现中,会把被观察者对象自身通过update方法传递给观察者。
如某APP推出了新的版本,通知信息只会简单的列出版本号和下载地址,如果用户需要升级,还需要调用下载接口完成升级。