观察者模式(发布-订阅模式 Publish Subscribe Pattern):定义了一种一对多的关系,让多个观察对象同时监听一个主题对象,当主题对象状态发生变化时会通知所有观察者,是它们能够自动更新自己,是一种行为设计模式。

观察者模式的结构

1,Publisher 会向其他对象发送值得关注的事件notifySubscribers。事件会在发布者自身状态改变或执行特定行为后发生。发布者中包含一个允许新订阅者加入subscribe和当前订阅者离开列表unsubscribe的订阅构架。

2,当新事件发生时,发送者会遍历订阅列表并调用每个订阅者对象的通知方法。该方法是在订阅者接口中声明的。

3,Subscriber 接口声明了通知接口。在绝大多数情况下,该接口仅包含一个update方法。该方法可以拥有多个参数,使发布者能在更新时传递事件的详细信息。

4,Concrete Subscriber 具体订阅者,可以执行一些操作来回应发布者的通知。所有具体订阅者类都实现了同样的接口,发布者不与具体类相耦合。

5,订阅者通常需要一些上下文信息来正确地处理更新。因此,发布者通常会将一些上下文数据作为通知方法的参数进行传递。发布者也可将自身作为参数进行传递,使订阅者直接获取所需的数据。

6,Client 会分别创建发布者和订阅者对象,然后为订阅者注册发布者更新。

观察者代码

 from __future__ import annotations
from abc import ABC, abstractmethod
from random import randrange
from typing import List class Subject(ABC):
"""
声明一组用于管理订阅者的方法
""" @abstractmethod
def attach(self, observer: Observer) -> None:
"""
添加观察者到subject.
"""
pass @abstractmethod
def detach(self, observer: Observer) -> None:
"""
从subject删除观察者.
"""
pass @abstractmethod
def notify(self) -> None:
"""
通知观察者事件的发生.
"""
pass class ConcreteSubject(Subject):
"""
Subject有一些状态,状态变更需要通知观察者
"""
# Subject的状态,所有的订阅者都要有,
_state: int = None # 订阅用户列表
_observers: List[Observer] = [] def attach(self, observer: Observer) -> None:
print("Subject: Attached an observer.")
self._observers.append(observer) def detach(self, observer: Observer) -> None:
self._observers.remove(observer) # 通知所有订阅者
def notify(self) -> None:
"""
通知接口,触发了所有的订阅用户的update方法
""" print("Subject: Notifying observers...")
for observer in self._observers:
observer.update(self) def some_business_logic(self) -> None:
"""
一些业务逻辑块,处理业务逻辑后,也可能会触发状态的变更,需要调用notify通知所有订阅者,
""" print("\nSubject: state change")
self._state = randrange(0, 10) print(f"Subject: My state has changed to: {self._state}")
self.notify() class Observer(ABC):
"""
订阅者声明对象使用的update.
""" @abstractmethod
def update(self, subject: Subject) -> None:
"""
接收到状态变更.
"""
pass """
具体订阅者,对状态的变更做出具体反应
""" class ConcreteObserverA(Observer):
def update(self, subject: Subject) -> None:
if subject._state < 3:
print("ConcreteObserverA: Reacted to the event") class ConcreteObserverB(Observer):
def update(self, subject: Subject) -> None:
if subject._state == 0 or subject._state >= 2:
print("ConcreteObserverB: Reacted to the event") if __name__ == "__main__":
# The client code. subject = ConcreteSubject() observer_a = ConcreteObserverA()
subject.attach(observer_a) observer_b = ConcreteObserverB()
subject.attach(observer_b) subject.some_business_logic()
subject.some_business_logic() subject.detach(observer_a) subject.some_business_logic()

适用场景:

1,当一个对象状态的改变需要改变其他对象,或实际对象是事先未知的或动态变化的时,可使用观察者模式。

2,当应用中的一些对象必须观察其他对象时,可使用该模式。

优点:

符合开闭原则,不用修改发布者代码就能引入新的订阅者类。

可以在运行时建立对象之间的联系。

缺点:

订阅者的通知顺序是随机的

作者:Andy
出处:http://www.cnblogs.com/onepiece-andy/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

大话设计模式Python实现-观察者模式的更多相关文章

  1. 大话设计模式--Python

    作者:五岳 出处:http://www.cnblogs.com/wuyuegb2312 上一周把<大话设计模式>看完了,对面向对象技术有了新的理解,对于一个在C下写代码比较多.偶尔会用到一 ...

  2. 大话设计模式C++版——观察者模式

    观察者模式是一种类似于消息分发的模式,用于一个任务需要被多个对象监听的场景,或者成员对象需要反向通知类对象的情况,是一种很有用的设计模式.    这里以大话设计模式中的例子为例,办公室员工A.B.C在 ...

  3. 大话设计模式Python实现-迭代器模式

    迭代器模式(Iterator Pattern):提供方法顺序访问一个聚合对象中各元素,而又不暴露该对象的内部表示. 下面是一个迭代器模式的demo: #!/usr/bin/env python # - ...

  4. 大话设计模式Python实现-解释器模式

    解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 下面是一个解释器模式的demo: #!/usr/ ...

  5. 大话设计模式Python实现- 享元模式

    享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象. 下面是一个享元模式的demo: #!/usr/bin/env python # -*- coding:utf- ...

  6. 大话设计模式Python实现-中介者模式

    中介者模式(Mediator Pattern):用一个对象来封装一系列的对象交互,中介者使各对象不需要显示地相互引用,从而使耦合松散,而且可以独立地改变它们之间的交互. 下面是一个中介者模式的demo ...

  7. 大话设计模式Python实现-职责链模式

    职责链模式(Chain Of Responsibility):使多个对象都有机会处理请求,从而避免发送者和接收者的耦合关系.将对象连成链并沿着这条链传递请求直到被处理 下面是一个设计模式的demo: ...

  8. 大话设计模式Python实现-命令模式

    命令模式(Command Pattern):将请求封装成对象,从而使可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤消的操作. 下面是一个命令模式的demo: #!/usr/bi ...

  9. 大话设计模式Python实现-桥接模式

    桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化. 下面是一个桥接模式的demo: #!/usr/bin/env python # -*- coding: ...

随机推荐

  1. IT兄弟连 HTML5教程 HTML5和HTML的关系

    HTML5开发现在很火爆,是一门技术,更是一个概念.可以让我们的工作模式.交互模式以及对应用和游戏的体验有了翻天覆地的变化,很多人都知道HTML5这门技术,也常把HTML5读作H5(简称).其实一些外 ...

  2. Zabbix 系列文章

    Zabbix 所有文章目录 本系列文章都基于 Zabbix 4.0 , Zabbix 4.0 是属于长期支持版本,其它的长期支持版本有 3.0 .2.2 . 官方已经有中文文档, 官方文档链接: Za ...

  3. .net 通过反射实现两个相同结构实体类的转换

    public static T2 CopyToModel<T1, T2>(T1 source) { T2 model = default(T2); PropertyInfo[] pi = ...

  4. SSM(七)在JavaWeb应用中使用Redis

    前言 先来看一张效果图: 作用就是在每次查询接口的时候首先判断Redis中是否有缓存,有的话就读取,没有就查询数据库并保存到Redis中,下次再查询的话就会直接从缓存中读取了.Redis中的结果:之后 ...

  5. 敏捷软件开发_实例2<四>

    敏捷软件开发_实例2 上一章中对薪水支付案例的用例和类做了详细的阐述,在本篇会介绍薪水支付案例包的划分和数据库,UI的设计. 包的划分 一个错误包的划分 为什么这个包是错误的: 如果对classifi ...

  6. python 通过使用pandas的实现的Excel的批量转换CSV文件的处理

    ---恢复内容开始--- 最近同事在处理文件导入的时候需要把一批文件换成CSV的格式,但是直觉修改后缀是不生效的,而且xlsx和xls的文件没法直接换成CVS的文件,所以找了一下方式,并且自己实现了p ...

  7. 【LeetCode】437. 路径总和 III

    437. 路径总和 III 给定一个二叉树,它的每个结点都存放着一个整数值. 找出路径和等于给定数值的路径总数. 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点 ...

  8. ElasticSearch安装及运行的坑

    一.确认centos系统是为64位的,x86的不可以安装 1. 下载elasticsearch包 2. 用 tar -zxvf 解压包 3. 增加一个elk用户,elasticsearch7不可用ro ...

  9. 导入部署 hand

    差价导入部署步骤如下: 执行视图,包. 定义消息,验证的时候使用(XXC1003DFM_BI_001 到 XXC1003DFM_BI_007,含中英文). 通用导入设置: 电子表元数据管理,含导入正确 ...

  10. ORA-1562 and ORA-1650 Unable to Extend Rollback Segment (Doc ID 1066542.6)

    ORA-1562 and ORA-1650 Unable to Extend Rollback Segment (Doc ID 1066542.6) APPLIES TO: Oracle Databa ...