设计模式Python版 观察者模式

server/2025/3/4 0:32:12/

文章目录


前言

GOF设计模式分三大类:

  • 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
  • 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
  • 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。

一、观察者模式

观察者模式(Observer Pattern)

  • 定义:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

  • 解决问题:如何实现对象之间一对多的联动?

  • 使用场景:

    • 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁。
    • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……
  • 组成:

    • Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时定义了通知方法notify()
    • ConcreteSubject(具体目标):具体目标是目标类的子类,通常包含有经常发生改变的数据。当它的状态发生改变时,向其各个观察者发出通知。
    • Observer(观察者):观察者将对观察目标的改变做出反应。观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。
    • ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致。
  • 补充说明:

    • 一个对象的状态或行为的变化将导致其他对象的状态或行为也发生改变,它们之间将产生联动,正所谓“触一而牵百发”。
    • 观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者。
    • 一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。
    • 观察者模式是一种使用频率非常高的设计模式
  • 优点:

  • 缺点:

    • 将所有的观察者都通知到会花费很多时间
    • 如果在观察者和观察目标之间存在循环依赖,可能导致系统崩溃
    • 仅仅只是知道观察目标发生了变化,但不知道具体变化

在这里插入图片描述

二、观察者模式示例

使用观察者模式来进行多人联机对战游戏的设计

  • 多个玩家可以加入同一战队组成联盟,当战队中某一成员受到敌人攻击时将给所有其他盟友发送通知,盟友收到通知后将做出响应。
  • AllyControlCenter充当目标类,ConcreteAllyControlCenter充当具体目标类,Observer充当抽象观察者,Player充当具体观察者。
  • 实现了两次对象之间的联动:当一个游戏玩家Player对象的beAttacked()方法被调用时,将调用AllyControlCenter的notifyObserver()方法来进行处理,而在notifyObserver()方法中又将调用其他Player对象的help()方法。
    • Player.beAttacked() → AllyControlCenter.notifyObserver() → Player.help()
python">"""观察者模式"""### 目标类class AllyControlCenter:"""战队控制中心"""def __init__(self, ally_name):self.ally_name = ally_name  # 战队名称self.players: list[Observer] = []  # 用于存储战队成员def join(self, obs: "Observer"):"""注册方法"""print(f"{obs.name} 加入 {self.ally_name} 战队!")self.players.append(obs)def quit(self, obs: "Observer"):"""注销方法"""print(f"{obs.name} 退出 {self.ally_name} 战队!")self.players.remove(obs)def notify_observer(self, name: str):"""通知方法"""raise NotImplementedError### 具体目标类class ConcreteAllyControlCenter(AllyControlCenter):"""具体战队控制中心"""def __init__(self, ally_name):super().__init__(ally_name)print(f"{self.ally_name} 战队组建成功!")print("#" * 10)def notify_observer(self, name):print(f"{self.ally_name} 战队紧急通知,盟友 {name} 遭受敌人攻击!")# 遍历调用每一个盟友(自己除外)的支援方法for obs in self.players:if obs.name != name:obs.help()### 抽象观察者class Observer:def __init__(self, name):self.name = namedef help(self):"""支援盟友方法"""raise NotImplementedErrordef be_attacked(self, acc: AllyControlCenter):"""遭受攻击方法"""raise NotImplementedError### 具体观察者class Player(Observer):"""战队成员"""def help(self):print(f"坚持住,{self.name} 来支援你!")def be_attacked(self, acc):"""当遭受攻击时将调用战队控制中心类的通知方法来通知盟友"""print(f"{self.name} 被攻击!")acc.notify_observer(self.name)
  • 客户端代码
python">if __name__ == "__main__":acc = ConcreteAllyControlCenter("金陵十二钗")player1 = Player("林黛玉")acc.join(player1)player2 = Player("薛宝钗")acc.join(player2)player3 = Player("贾元春")acc.join(player3)player4 = Player("贾探春")acc.join(player4)player1.be_attacked(acc)
  • 输出结果
金陵十二钗 战队组建成功!
##########
林黛玉 加入 金陵十二钗 战队!
薛宝钗 加入 金陵十二钗 战队!
贾元春 加入 金陵十二钗 战队!
贾探春 加入 金陵十二钗 战队!
林黛玉 被攻击!
金陵十二钗 战队紧急通知,盟友 林黛玉 遭受敌人攻击!
坚持住,薛宝钗 来支援你!
坚持住,贾元春 来支援你!
坚持住,贾探春 来支援你!

您正在阅读的是《设计模式Python版》专栏!关注不迷路~


http://www.ppmy.cn/server/172205.html

相关文章

TCP 三次握手与四次挥手

TCP 三次握手与四次挥手知识总结 一、TCP 连接与断开的核心机制 1. 三次握手(建立连接) 目的: 建立客户端与服务端之间的双向传输通道,确保双方都能确认对方的接收和发送能力,为后续的数据传输奠定可靠基础。 流程…

【AIGC系列】3:Stable Diffusion模型原理介绍

AIGC系列博文: 【AIGC系列】1:自编码器(AutoEncoder, AE) 【AIGC系列】2:DALLE 2模型介绍(内含扩散模型介绍) 【AIGC系列】3:Stable Diffusion模型原理介绍 【AIGC系列】4&#xff1…

【网络安全 | 渗透测试】GraphQL精讲二:发现API漏洞

未经许可,不得转载。 推荐阅读:【网络安全 | 渗透测试】GraphQL精讲一:基础知识 文章目录 GraphQL API 漏洞寻找 GraphQL 端点通用查询常见的端点名称请求方法初步测试利用未清理的参数发现模式信息使用 introspection探测 introspection运行完整的 introspection 查询可视化…

阿里云服务器宝塔终端如何创建fastadmin插件

1. 进入宝塔终端 2. cd / 进入根目录 3. FastAdmin 可以通过命令行创建一个插件,首先我们将工作目录切换到我们的项目根目录,也就是think文件所在的目录。 cd /var/www/yoursite/ 4.然后我们在命令行输入 php think addon -a mydemo -c create …

目标检测——数据处理

1. Mosaic 数据增强 Mosaic 数据增强步骤: (1). 选择四个图像: 从数据集中随机选择四张图像。这四张图像是用来组合成一个新图像的基础。 (2) 确定拼接位置: 设计一个新的画布(输入size的2倍),在指定范围内找出一个随机点(如…

火绒终端安全管理系统V2.0网络防御功能介绍

网络防御是指通过一系列技术、策略和措施,保护网络系统、数据和资源免受未经授权的访问、攻击、破坏或泄露。 火绒终端安全管理系统:网络防御功能包含网络入侵拦截、横向渗透防护、对外攻击检测、僵尸网络防护、Web服务保护、暴破攻击防护、远程登录防护…

广东GZ033-任务E:数据可视化(15 分)-用柱状图展示销售金额最高的6 个月

广东GZ033-任务E:数据可视化(15 分) 用柱状图展示销售金额最高的6 个月 编写Vue 工程代码, 读取虚拟机bigdata-spark 的/opt/data 目录下的 supermarket_visualization.csv,用柱状图展示2024 年销售金额最高的6 个月&a…

大白话解释深度学习中多尺度特征融合及其意义

想象一下,你正在看一幅城市街道的照片。在这张照片中,你可能会看到: 远处的小汽车,它们在图像中看起来很小。近处的大巴士,它们在图像中看起来很大。还有一些行人,他们可能在不同的距离上,大小…