观察者模式
定义
观察者模式(发布-订阅模式 Publish Subscribe Pattern):定义了一种一对多的关系,让多个观察对象同时监听一个主题对象,当主题对象状态发生变化时会通知所有观察者,使它们能够自动更新自己。
简单就是说你有一个观察者列表,这个列表中的函数或者某种功能都在观察某个事件的发生,一旦发生,这些函数或者功能就会自动执行。
场景
例如,员工趁老板不在,都在玩自己的东西,同时观察着前台小姐姐,前台小姐姐在老板回来的时候,发布通知让各同事回到工作状态。
实现
没有设计模式的实现
先看看没有使用观察者模式的实现代码
# 看股票的同学
class StockObserver:
def update(self):
print('看股票的同学 关闭股票行情,继续工作')
# 看NBA的同学
class NbaObserver:
def update(self):
print('看NBA的同学 关闭NBA,继续工作')
# 前台小姐姐
class Receptionist:
def notify(self):
print("老板回来了,各单位请注意...")
StockObserver().update()
NbaObserver().update()
if __name__ == "__main__":
receptionist = Receptionist()
receptionist.notify()
这样写,看似没有任何问题,但如果再出现几个调皮的同事,一个玩游戏的,一个打瞌睡的,一个。。。他们都需要知道老板回来。
程序就会变成下面这样
# 前台小姐姐
class Receptionist:
def notify(self):
print("老板回来了,各单位请注意...")
StockObserver().update()
NbaObserver().update()
PlayGameObserver().update()
SleepyObserver().update()
...
每次都要修改原来的代码,而且代码只会越来越庞大和复杂。
如果,在老板回来之前,看NBA的同学的NBA比赛看完了,不需要前台小姐姐通知了,又要改代码。
观察者模式实现
用观察者模式来实现上面的例子
# 抽象观察者类
class Observer(object):
def __init__(self, name, publish):
self.name = name
self.publish = publish
def update(self):
pass
# 具体观察者类-看股票的同学
class StockObserver(Observer):
def update(self):
print(self.publish.subject_status, self.name, '关闭股票行情,继续工作')
# 具体观察者类-看NBA的同学
class NbaObserver(Observer):
def update(self):
print(self.publish.subject_status, self.name, '关闭NBA,继续工作')
# 抽象发布者类
class Publish(object):
def attach(self, observer):
pass
def detach(self, observer):
pass
def notify(self):
pass
# 具体发布者类-前台小姐姐
class Receptionist(Publish):
def __init__(self):
self.observer_list = []
self.subject_status = ""
def attach(self, observer):
self.observer_list.append(observer)
def detach(self, observer):
self.observer_list.remove(observer)
def notify(self):
self.subject_status = "老板回来了"
print("老板回来了,各单位请注意...")
for item in self.observer_list:
item.update()
if __name__ == "__main__":
publisher = Receptionist()
stock = StockObserver('看股票的同学', publisher)
nba = NbaObserver('看NBA的同学', publisher)
publisher.attach(stock)
publisher.attach(nba)
publisher.notify()
为什么要用观察者模式?
采用观察者模式,如果再来一个打游戏的同学,他也需要知道老板回来,那么直接订阅前台小姐姐的通知即可,不需要修改发布者和观察者的代码;
如果,在老板回来之前,看NBA的同学的NBA比赛看完了,那么就可以取消订阅前台小姐姐的通知,也不需要修改发布者和观察者的代码。
优点
使彼此交互的对象保持松耦合。
当需要添加其他对象时,无需对发布者和观察者做任何修改。
可以随时添加和删除观察者。
缺点
实现不当可能会增加复杂性,导致性能降低。
通知有时是不可靠的,并导致竞争条件或不一致性。