[Python设计模式] 第14章 老板来了——观察者模式
github地址:https://github.com/cheesezh/python_design_patterns
题目
用程序模拟以下情景,在一个办公室里,当老板进门的时候,前台秘书就偷偷通知办公室里的同事:“老板来了”,办公室里的同事就会停止观看股票,继续工作。
基础版本
class Secretary():
"""
通知者
"""
def __init__(self):
self.observers = []
self.action = None
def attach(self, observer):
self.observers.append(observer)
def notify(self):
for observer in self.observers:
observer.update()
class Observers():
"""
观察者
"""
def __init__(self, name, informer):
self.name = name
self.informer = informer
def update(self):
print("{} {}关闭股票行情, 继续工作.".format(self.informer.action, self.name))
def main():
informer = Secretary()
hh = Observers("贺贺", informer)
mm = Observers("曼曼", informer)
informer.attach(hh)
informer.attach(mm)
informer.action = "老板来了!"
informer.notify()
main()
老板来了! 贺贺关闭股票行情, 继续工作.
老板来了! 曼曼关闭股票行情, 继续工作.
点评
- 上述代码基本能够表示设定的场景,但是有一个问题,“通知者”和“观察者”这两个类互相耦合,即双向耦合;
- 假设另一类“观察者”不看股票,而是在看NBA比赛,那么这类“观察者”对应的update操作就不应该是“关闭股票行情”,而是“关闭NBA直播”;
- 此外,除了前台秘书可以作为“通知者”,老板其实也是“通知者”,当老板来了,各个“观察者”也应该及时回到工作状态;
- 综上,需要对“观察者”和“通知者”进行进一步抽象
改进版本——双向解耦
from abc import ABCMeta,abstractmethod
class Informer():
"""
抽象通知者
"""
__metaclass__ = ABCMeta
@abstractmethod
def attach(self, observer):
pass
@abstractmethod
def detach(self, observer):
pass
@abstractmethod
def notify(self):
pass
class Boss(Informer):
"""
具体通知者
"""
def __init__(self):
self.observers = []
self.action = None
# 老板特有的初始化操作
def attach(self, observer):
print("聘用:{}".format(observer.name))
self.observers.append(observer)
def detach(self, observer):
print("解聘:{}".format(observer.name))
self.observers.remove(observer)
def notify(self):
print("--老板发出强大的气场--")
for o in self.observers:
o.update()
class Secretary(Informer):
"""
具体通知者
"""
def __init__(self):
self.observers = []
self.action = None
# 秘书特有的初始化操作
def attach(self, observer):
print("关系和谐:{}".format(observer.name))
self.observers.append(observer)
def detach(self, observer):
print("产生矛盾:{}".format(observer.name))
self.observers.remove(observer)
def notify(self):
print("--秘书发送即时消息--")
for o in self.observers:
o.update()
class Observer():
"""
抽象观察者
"""
__mataclass__ = ABCMeta
@abstractmethod
def __init__(self, name, informer): # 之所以要有informer,是为了在观察者内部访问到informer的对象
pass
@abstractmethod
def update(self):
pass
class StockObserver(Observer):
"""
具体观察者
"""
def __init__(self, name, informer):
self.name = name
self.informer = informer
def update(self):
print("{} {}关闭股票行情, 继续工作.".format(self.informer.action, self.name))
class NBAObserver(Observer):
"""
具体观察者
"""
def __init__(self, name, informer):
self.name = name
self.informer = informer
def update(self):
print("{} {}关闭NBA直播, 继续工作.".format(self.informer.action, self.name))
def main():
boss = Boss()
hh = StockObserver("贺贺", boss)
mm = NBAObserver("曼曼", boss)
boss.attach(hh)
boss.attach(mm)
boss.action = "我回来了!"
boss.notify()
secretary = Secretary()
mr = StockObserver("鸣人", secretary)
zz = NBAObserver("佐助", secretary)
xy = NBAObserver("小樱", secretary)
secretary.attach(mr)
secretary.attach(zz)
secretary.attach(xy)
secretary.detach(xy)
secretary.action = "老板回来了!"
secretary.notify()
main()
聘用:贺贺
聘用:曼曼
--老板发出强大的气场--
我回来了! 贺贺关闭股票行情, 继续工作.
我回来了! 曼曼关闭NBA直播, 继续工作.
关系和谐:鸣人
关系和谐:佐助
关系和谐:小樱
产生矛盾:小樱
--秘书发送即时消息--
老板回来了! 鸣人关闭股票行情, 继续工作.
老板回来了! 佐助关闭NBA直播, 继续工作.
观察者模式(发布-订阅模式)
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
Subject类,可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
Observer类,即抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个update方法。
ConcreteSubject类,叫做具体主题或者具体通知者,将有关状态存入具体观察者对象。在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
ConcreteObserver类,即具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如有需要,具体观察者角色可以保存一个指向具体主题对象的引用,以便获取具体主题对象的状态。
观察者模式特点
讲一个系统分割成一系列相互写作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护,扩展和重用都带来不便[DP]。而观察者的关键对象使主题Subject和观察者Observer,一个主题可以有任意树木的依赖它的Observer,一旦Subject状态发生变化,所有的Observer都可以得到通知。
那么什么时候使用观察者模式呢?
当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,需要考虑使用观察者模式。另外,当一个抽象模型有两个方面,其中一个方面依赖另一个方面,这时候使用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
总地来将,观察者模式所做的工作其实就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体实现。从而使得各自的变化不会影响另一边的变化。
[Python设计模式] 第14章 老板来了——观察者模式的更多相关文章
- [Python设计模式] 第21章 计划生育——单例模式
github地址:https://github.com/cheesezh/python_design_patterns 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式 ...
- [Python设计模式] 第16章 上班,干活,下班,加班——状态模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 用代码模拟一天的工作状态,上午状态好,中午想睡觉,下午渐恢复,加班苦煎熬. ...
- [Python设计模式] 第1章 计算器——简单工厂模式
github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...
- [Python设计模式] 第24章 加薪审批——职责链模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 用程序模拟以下情景 员工向经理发起加薪申请,经理无权决定,需要向总监汇报, ...
- [Python设计模式] 第22章 手机型号&软件版本——桥接模式
github地址:https://github.com/cheesezh/python_design_patterns 紧耦合程序演化 题目1 编程模拟以下情景,有一个N品牌手机,在上边玩一个小游戏. ...
- [Python设计模式] 第9章 如何准备多份简历——原型模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 设计一个简历类,必须有姓名,可以设置性别和年龄,即个人信息,可以设置曾就职 ...
- [Python设计模式] 第7章 找人帮忙追美眉——代理模式
github地址:https://github.com/cheesezh/python_design_patterns 题目1 Boy追求Girl,给Girl送鲜花,送巧克力,送洋娃娃. class ...
- [Python设计模式] 第28章 男人和女人——访问者模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 用程序模拟以下不同情况: 男人成功时,背后多半有一个伟大的女人: 女人成功 ...
- [Python设计模式] 第26章 千人千面,内在共享——享元模式
github地址:https://github.com/cheesezh/python_design_patterns 背景 有6个客户想做产品展示网站,其中3个想做成天猫商城那样的"电商风 ...
随机推荐
- POJ2676 Sudoku 舞蹈链 DLX
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目(传送门) 题意概括 给出一个残缺的数独,求解.SPJ 题解 DLX + 矩阵构建 (两个传送门) 代码 #includ ...
- day 42 mycql 查询操作,重点中的重点
数据库的查询操作是重点中的重点,最核心的内容就是它! 在查询时关键字的定义顺序: select distinct(select-list) from (left-table) (type-join) ...
- 第K人||约瑟夫环(链表)
http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4442 很容易超时 通过数组来记录,删除 //数组从1开始好像不行 后面一些数字就乱码了,因 ...
- Jquery操作一遍过
什么是jQuery对象? jQuery 对象就是通过jQuery包装DOM对象后产生的对象.jQuery 对象是 jQuery 独有的. 如果一个对象是 jQuery 对象, 那么它就可以使用 jQu ...
- git命令详解( 七 )
此为git命令详解的第七篇 这章我们可以来逐渐揭开 git push.fetch 和 pull 的神秘面纱了.我们会逐个介绍这几个命令,它们在理念上是非常相似的. git push的参数 git ...
- iOS APP提交上架流程
转载自CocoaChina,链接地址:http://www.cocoachina.com/bbs/read.php?tid=330302 后面问题我也遇到了,参考该文章解决的 转自http://blo ...
- java菜鸟之微信分享
前言:我终于理解了什么叫做教科书:教科书就是把一些简单容易的知识写成一堆谁都看不懂的书,这,就简称“教科书” 这些天接触到微信分享以及回调的问题,因为之前没接触过,所以这次做这个分享,碰了一点点壁,特 ...
- javascript 伪数组和转化为标准数组
1: 什么是伪数组 伪数组是一个含有length属性的json对象, 它是按照索引的方式存储数据, 它并不具有数组的一些方法,只能能通过Array.prototype.slice转换为真正的数组,并且 ...
- [转]REMOTE_ADDR,HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR
午睡一觉醒来,突然想伪造IP地址.搜了一下,Mark. 源地址:http://www.cnblogs.com/lmule/archive/2010/10/15/1852020.html ------- ...
- [ZJOI2013]K大数查询
Description: 给定一个序列,支持两种操作 1.在[L,R]的每个位置上加上一个数 (注意一个位置上有多个数) 2.查询[L,R]上所有数中的第K大 Hint: \(n,m<=5e4\ ...