大话设计模式Python实现-观察者模式
观察者模式(发布-订阅模式 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实现-观察者模式的更多相关文章
- 大话设计模式--Python
作者:五岳 出处:http://www.cnblogs.com/wuyuegb2312 上一周把<大话设计模式>看完了,对面向对象技术有了新的理解,对于一个在C下写代码比较多.偶尔会用到一 ...
- 大话设计模式C++版——观察者模式
观察者模式是一种类似于消息分发的模式,用于一个任务需要被多个对象监听的场景,或者成员对象需要反向通知类对象的情况,是一种很有用的设计模式. 这里以大话设计模式中的例子为例,办公室员工A.B.C在 ...
- 大话设计模式Python实现-迭代器模式
迭代器模式(Iterator Pattern):提供方法顺序访问一个聚合对象中各元素,而又不暴露该对象的内部表示. 下面是一个迭代器模式的demo: #!/usr/bin/env python # - ...
- 大话设计模式Python实现-解释器模式
解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子. 下面是一个解释器模式的demo: #!/usr/ ...
- 大话设计模式Python实现- 享元模式
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象. 下面是一个享元模式的demo: #!/usr/bin/env python # -*- coding:utf- ...
- 大话设计模式Python实现-中介者模式
中介者模式(Mediator Pattern):用一个对象来封装一系列的对象交互,中介者使各对象不需要显示地相互引用,从而使耦合松散,而且可以独立地改变它们之间的交互. 下面是一个中介者模式的demo ...
- 大话设计模式Python实现-职责链模式
职责链模式(Chain Of Responsibility):使多个对象都有机会处理请求,从而避免发送者和接收者的耦合关系.将对象连成链并沿着这条链传递请求直到被处理 下面是一个设计模式的demo: ...
- 大话设计模式Python实现-命令模式
命令模式(Command Pattern):将请求封装成对象,从而使可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可撤消的操作. 下面是一个命令模式的demo: #!/usr/bi ...
- 大话设计模式Python实现-桥接模式
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化. 下面是一个桥接模式的demo: #!/usr/bin/env python # -*- coding: ...
随机推荐
- Python代码报错看不懂?记住这20个报错提示单词轻松解决bug
1. syntaxerror: invalid syntax语法错误:无效语法 1) syntax [ˈsɪntæks] 语法.句法 2) error [ˈerər] 错误 3) invalid [ɪ ...
- JVM基础详解
JVM基础解析(一) Java里面有 JDK ,JRE, JVM ,这三者的关系是怎么样的呢? JDK是编译时环境: 整个Java的核心,包括了Java运行环境JRE.Java工具和Java基础类库 ...
- LeetCode 599: 两个列表的最小索引总和 Minimum Index Sum of Two Lists
题目: 假设 Andy 和 Doris 想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示. Suppose Andy and Doris want to cho ...
- Asp.net ------ 开发web 网站
HTML文件变成可以动态界面,经常会变成后缀有: 使用 .NET 开发的展示界面后缀是 .aspx 使用java 开发的展示界面后缀是 .jsp 使用php 开发的展示界面后缀是 .php 本 ...
- url中拼接中文参数,后台接收为乱码的问题
遇到在URL中拼接中文的参数,后台拿到的数据为乱码的问题,这里来说一下问题出现的原因与解决方法. 大家比较关心的应该是解决的方法,因此先说解决方法. 解决方法 解决的方法是在客户端对这个中文参数进行编 ...
- Oracle - 截取指定日期的alert log
工作中DBA经常会查看alert log来检查数据库后台都记录了些什么日志,如果只想看某一天或者某段时间范围的日志,能够把这些日志从大的alert log中截取下来放到一个单独的文件中,对于查看和下载 ...
- python将oracle数据库保存到excel
上代码: import pandas as pd import SqlHelper.ORACLE as ORA if __name__ == '__main__': #连接数据库 ms = ORA.O ...
- python基础(19):random模块、time模块、sys模块、os模块
1. random模块 导入的是random模块,格式是: import random 1.1 随机小数 取随机小数 : 数学计算. print(random.random()) # 取0-1之间的小 ...
- PHP常量以及基本数据类型
1.常量 1.1用define()函数定义常量 define(常量名,值,[是否区别大小写]) true表示不区分大小写,默认是false 常量名前没有$符 常量名推荐使用大写 1.2.定义 ...
- oracle 利用序列与触发器实现列自增
实现步骤:先创建序列,后创建触发器 1.创建序列 create sequence 序列名 increment start maxvalue ; 2.创建触发器 create or replace tr ...