观察者模式(发布-订阅模式 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. SpringBoot系列之Spring容器添加组件方式

    SpringBoot系列之Spring容器添加组件方式 本博客介绍SpringBoot项目中将组件添加到Spring容器中的方法,SpringBoot项目有一个很明显的优点,就是不需要再编写xml配置 ...

  2. clientHeight—scrollHeight—offsetHeight三者的区别

    clientHeight,scrollHeight,offsetHeight 这三个dom属性有时让人觉得相似但又不相似 以前对它们的理解也有一些模糊,现在总结一下,方便以后复习 clientHeig ...

  3. PHP判断设备访问来源

    /** * 判断用户请求设备是否是移动设备 * @return bool */ function isMobile() { //如果有HTTP_X_WAP_PROFILE则一定是移动设备 if (is ...

  4. 【CF1172E】Nauuo and ODT(Link-Cut Tree)

    [CF1172E]Nauuo and ODT(Link-Cut Tree) 题面 CF 给你一棵树,每个节点有一个颜色. 定义一条路径的权值为路径上不同颜色的数量.求所有有向路径的权值和. 有\(m\ ...

  5. node-sass安装失败处理办法

    参考: https://npm.taobao.org/mirrors https://lzw.me/a/node-sass-install-helper.html 设置环境变量安装 SASS_BINA ...

  6. Implement Custom Business Classes and Reference Properties 实现自定义业务类和引用属性(XPO)

    In this lesson, you will learn how to implement business classes from scratch. For this purpose, the ...

  7. 同样是高并发,QQ/微博/12306的架构难度一样吗?

    开篇 同一个用户并发扣款时,有一定概率出现数据不一致,可以使用CAS乐观锁的方式,在不降低吞吐量,保证数据的一致性: UPDATE t_yue SET money=$new_money WHERE u ...

  8. 定制Dynamics CRM标准导出功能:不能导出指定列的值

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复239或者20161203可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  9. qt 使用OpenCV

    使用MinGW编译OpenCV源码 下载OpenCV源码.CMake编译工具 编译安装完: Qt工程配置 INCLUDEPATH += D:/qt_work/opencv/build/install/ ...

  10. SRDC - ORA-1555 during Export: Checklist of Evidence to Supply (Doc ID 1682706.1)

    SRDC - ORA-1555 during Export: Checklist of Evidence to Supply (Doc ID 1682706.1) Action Plan 1. Exe ...