github地址:https://github.com/cheesezh/python_design_patterns

题目

用程序模拟以下情景,在一个办公室里,当老板进门的时候,前台秘书就偷偷通知办公室里的同事:“老板来了”,办公室里的同事就会停止观看股票,继续工作。

基础版本

class Secretary():"""通知者"""def __init__(self):self.observers = []self.action = Nonedef 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 = nameself.informer = informerdef 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,abstractmethodclass Informer():"""抽象通知者"""__metaclass__ = ABCMeta@abstractmethoddef attach(self, observer):pass@abstractmethoddef detach(self, observer):pass@abstractmethoddef notify(self):passclass 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@abstractmethoddef __init__(self, name, informer):  # 之所以要有informer,是为了在观察者内部访问到informer的对象pass@abstractmethoddef update(self):passclass StockObserver(Observer):"""具体观察者"""def __init__(self, name, informer):self.name = nameself.informer = informerdef update(self):print("{} {}关闭股票行情, 继续工作.".format(self.informer.action, self.name))class NBAObserver(Observer):"""具体观察者"""def __init__(self, name, informer):self.name = nameself.informer = informerdef 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都可以得到通知。

那么什么时候使用观察者模式呢?

当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,需要考虑使用观察者模式。另外,当一个抽象模型有两个方面,其中一个方面依赖另一个方面,这时候使用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。

总地来将,观察者模式所做的工作其实就是在解耦,让耦合的双方都依赖于抽象,而不是依赖于具体实现。从而使得各自的变化不会影响另一边的变化。

转载于:https://www.cnblogs.com/CheeseZH/p/9440617.html

[Python设计模式] 第14章 老板来了——观察者模式相关推荐

  1. Python tkinter -- 第14章 列表框(Listbox)属性

    第14章 列表框(Listbox) 列表框控件显示多行文本,用户可以选中一行或者多行.所有的文本只能使用一种字体,不能混合使用多种字体. 14.1 属性 常用的参数列表如下: 属性 描述 active ...

  2. [大话设计模式C++版] 第14章 老板回来,我不知道 —— 观察者模式

    源码可以在这里找到 大话设计模式C++版 双向耦合的代码 //Secretary.h 秘书类 #include <QList>using namespace std; class Stoc ...

  3. [Python设计模式] 第21章 计划生育——单例模式

    github地址:https://github.com/cheesezh/python_design_patterns 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式 ...

  4. [Python设计模式] 第1章 计算器——简单工厂模式

    github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...

  5. python工作状态_[Python设计模式] 第16章 上班,干活,下班,加班——状态模式

    题目 用代码模拟一天的工作状态,上午状态好,中午想睡觉,下午渐恢复,加班苦煎熬. 基础版本--函数版 hour = 0 work_finished = False def write_program( ...

  6. 『流畅的Python』第14章:可迭代的对象、迭代器和生成器

  7. [Python设计模式] 第8章 学习雷锋好榜样——工厂方法模式

    github地址:https://github.com/cheesezh/python_design_patterns 简单工厂模式 v.s. 工厂方法模式 以简单计算器为例,对比一下简单工厂模式和工 ...

  8. [Python设计模式] 第17章 程序中的翻译官——适配器模式

    github地址:https://github.com/cheesezh/python_design_patterns 适配器模式 适配器模式,将一个类的接口转换成客户希望的另外一个接口.Adapte ...

  9. python 图片识别服装_[Python设计模式] 第6章 衣服搭配系统——装饰模式

    题目 设计一个控制台程序,可以给人搭配嘻哈风格(T恤,垮裤,运动鞋)或白领风格(西装,领带,皮鞋)的衣服并展示,类似QQ秀那样的. 基础版本 class Person(): def __init__( ...

  10. python打折简单程序每满_[Python设计模式] 第2章 商场收银软件——策略模式

    题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计算总价. 基础版本 price = float(input("输入商品单价:")) number = ...

最新文章

  1. C#中Invoke的用法
  2. Eclipse中启动tomcat报错:A child container failed during start
  3. 七十二、区间合并,插入求交集, 删除被覆盖区间
  4. java floatmath_《Java1.doc
  5. VIM常用的编辑操作
  6. 有东西,可以倚老卖老,可以倚少卖少
  7. Python:安装pip
  8. Hbase 操作命令
  9. 电脑常见故障及解决方法
  10. JAVA中SSH框架
  11. html文字浮雕效果不起作用,CSS3实现文字浮雕效果,镂刻效果,火焰文字
  12. 谈一谈凑单页的那些优雅设计
  13. 在 Win10系统,所有程序默认都以管理员身份运行
  14. Utility.java的使用方法及家庭记账程序的制作
  15. wireshark使用Lua解析带有固定头和长度
  16. b站coderwhy老师_Vue项目开发-仿蘑菇街电商APP
  17. Solr 特点,为什么要用solr服务,
  18. 最年轻市长背后的选任悖
  19. Linux启动过程(开机启动顺序)
  20. [原创]无聊,没事做

热门文章

  1. LeetCode 刷题隔天忘怎么办?
  2. hdu 4334 Trouble 排序+优化 多校联合赛(四)第四题
  3. 如何使用 Numbers 筛选出特定种类的资料?
  4. hyperledger的个人分享
  5. iCalamus for Mac(版面设计工具)
  6. Git客户端Mac版:SmartGit
  7. Parallels Toolbox for mac(PD工具箱合集)
  8. Yate如何打开不同格式的音乐文件?
  9. Flutter第七期 - 布局总结篇
  10. koa项目用mongoose与mongodb交互,始终报错FormModel is not defined