【六】python观察者设计模式

6.1行为型模式简介

观察者设计模式是最简单的行为型模式之一,所以我们先简单了解一下行为型模式

  • 创建型模式的工作原理是基于对象的创建机制的。由于这些模式隔离了对象的创建细
    节,所以使得代码能够与要创建的对象的类型相互独立。
  • 结构型模式用于设计对象和类的结构,从而使它们可以相互协作以获得更大的结构。它们重点关注的是简化结构以及识别类和对象之间的关系。
  • 行为型模式,顾名思义,它主要关注的是对象的责任。它们用来处理对象之间的交互,以实现更大的功能。
    行为型模式建议:对象之间应该能够彼此交互,同时还应该是松散耦合的。

6.2 观察者设计模式

6.2.1 观察者设计模式介绍

在观察者设计模式中,对象(主题)维护了一个依赖(观察者)列表,以便主题可以使用观察者定义的任何方法通知所有观察者它所发生的变化。

  • 场景1:从属服务监视核心服务的状态变化
    例如用户在网站注册,其中用户服务组件负责用户在网站上的各种操作。假设我们有另外一个电子邮件的服务,它的作用是监视用户的状态并向用户发送电子邮件。在用户刚刚注册时,用户服务组件将调用电子邮件服务的方法,该方法将向用户发送电子邮件以进行账户验证。
    如果账户经过了验证,但信用度较低,则电子邮件服务将监视用户服务并向用户发送信用度过低的电子邮件警报。
    在这个网站应用中会存在一个许多其他服务所依赖的核心服务,该核心服务就是观察者观察/监视其变化的主题。
    当主题发生变化时,观察者应该改变自己的对象的状态,或者采取某些动作。
  • 场景2:广播或发布/订阅系统
    例如在博客中你跟其他人一样共同关注了某个作者并进行了专栏订阅服务,每当作者发布新博客作品时,你和其他订阅者就会收到通知。
    在观察者模式中,这里的博客就是维护订阅者或观察者列表的主题,当有新的文章添加到博客中时,所有观察者就会通过电子邮件或由观察者定义任何其他通知机制收到相应的通知。

6.2.2 观察者模式的主要作用:

  • 它定义了对象之间的一对多的依赖关系,从而使得一个对象中的任何更改都将自动通知给其他依赖对象;
  • 它封装了主题的核心组件观察者模式可用于以下多种场景;
  • 在分布式系统中实现事件服务;
  • 用作新闻机构的框架;
  • 股票市场也是观察者模式的一个大型场景下面是观察者设计模式的Python实现;

6.2.3 观察者模式的UML类图

现在我们将通过UML图来深入了解观察者模式
正如我们在上面所讨论的那样,观察者模式有两个主要角色:主题和观察者。让我们把这些角色放在一个UML 图中,看看这些类是如何交互的,如图所示。
在这里插入图片描述

通过观察这个UML图你就会发现,这个模式有3个主要角色

  • 主题(Subject):类Subject需要了解Observer。Subject类具有许多方法诸如register()和deregister()等,Observer可以通过这些方法注册到Subject 类中。
    因此,一个Subject可以处理多个Observer。
  • 观察者(observer):它为关注主题的对象定义了一个接口。它定义了observer需要实现的各个方法,以便在主题发生变化时能够获得相应的通知。
  • 具体观察者(Concreteobserver): 它用来保存应该与 Subject 的状态保持一致的状态。它实现了observer接口以保持其状态与主题中的变化相一致。
    这个流程非常简单。具体观察者通过实现观察者提供的接口向主题注册自己。每当状态发生变化时,该主题都会使用观察者提供的通知方法来通告所有具体观察者。

6.3 基于新闻发布案例的具体应用

6.3.1 需求场景:

新闻机构通常从不同地点收集新闻,并将其发布给订阅者。
由于信息是实时发送或接收的,所以新闻机构应该尽快向其订户公布该消息。
此外,随着技术的进步,订户不仅可以订阅报纸,而且可以通过其他的形式进行订阅,例如电子邮件、移动设备、短信或语音呼叫。
所以,我们还应该具备在将来添加任意其他订阅形式的能力,以便为未来的新技术做好准备。

6.3.2 代码实现

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
class NewsPublisher:# 新闻发布者,主题类:def __init__(self):self.subscribers = []self.latestNews = Nonedef attach(self, subscriber):# 订阅者用来注册self.subscribers.append(subscriber)def detach(self):# 注销订阅者,默认移出最后一个return self.subscribers.pop()def subscribers(self):# 返回所有订阅者列表return [type(x).name for x in self.subscribers]def notifySubscribers(self):# 通知所有订阅者for sub in self.subscribers:sub.update()def addNews(self, news):# 新增消息self.latestNews = newsdef getNews(self):# 返回新消息return "获取到消息:", self.latestNewsfrom abc import ABCMeta, abstractmethodclass Subscriber(metaclass=ABCMeta):"""观察者抽象基类,具体观察者继承该类,并实现抽象方法"""@abstractmethoddef update(self):# update()方法是由具体订阅者实现的,# 这样只要有新闻发布的时候它们都能得到 Subject(NewsPublishers)的相应通知。pass
class SMSSubscriber(Subscriber):"""短信观察者"""def __init__(self, publisher):# 初始化时进行注册self.publisher = publisherself.publisher.attach(self)def update(self):print(type(self).__name__, self.publisher.getNews())class EmailSubscriber(Subscriber):"""邮件观察者"""def __init__(self, publisher):self.publisher = publisherself.publisher.attach(self)def update(self):print(type(self).__name__, self.publisher.getNews())class AnyOtherSubscriber(Subscriber):# 其他观察者def __init__(self, publisher):self.publisher = publisherself.publisher.attach(self)def update(self):print(type(self).__name__, self.publisher.getNews())if __name__ == '__main__':news_publisher = NewsPublisher()for Subscribers in [SMSSubscriber, EmailSubscriber, AnyOtherSubscriber]:# 向主题中注册订阅者Subscribers(news_publisher)print("\n共有订阅者:", news_publisher.subscribers)news_publisher.addNews('添加消息:你好!')news_publisher.notifySubscribers()print("\n注销一个:", type(news_publisher.detach()).__name__)print("\n还剩订阅者:", news_publisher.subscribers)news_publisher.addNews('再次推送消息给订阅者')news_publisher.notifySubscribers()

6.4观察者模式的通知方式

有两种不同的方式可以通知观察者在主题中发生的变化。它们可以被分为推模型或拉模型。

6.4.1拉模型

在拉模型中,观察者扮演积极的角色
每当发生变化时,主题都会向所有已注册的观察者进行广播。
出现变化时,观察者负责获取相应的变化情况,或者从订户那里拉取数据。
拉模型的效率较低,因为它涉及两个步骤,第一步,主题通知观察者;第二步,观察者从主题那里提取所需的数据。

6.4.2 推模型

在推模型中,主题是起主导作用的一方,如下所示
与拉模型不同,变化由主题推送到观察者的。
在拉模型中,主题可以向观察者发送详细的信息(即使可能不需要)。当主题发送大量观察者用不到的数据时,会使响应时间过长。
由于只从主题发送所需的数据,所以能够提高性能。

6.5松耦合与观察者模式

松耦合是软件开发应该采用的重要设计原理之一。松耦合的主要目的是争取在彼此交互的对象之间实现松散耦合设计。
耦合是指一个对象对于与其交互的其他对象的了解程度。松耦合设计允许我们构建灵活的面向对象的系统,有效应对各种变化,因为它们降低了多个对象之间的依赖性。
松耦合架构具有以下特性:

  • 它降低了在一个元素内发生的更改可能对其他元素产生意外影响的风险;
  • 它使得测试、维护和故障排除工作更加简单;
  • 系统可以轻松地分解为可定义的元素;
    观察者模式提供了一种实现主题和观察者松耦合的对象设计模式。以下几条可以更好地解释这一点。
  • 主题对观察者唯一的了解就是它实现一个特定的接口。同时,它也不需要了解具体观察者类。
  • 可以随时添加任意的新观察者。
  • 添加新的观察者时,根本不需要修改主题。在本示例中,我们看到任意其他观察者可以任意添加/删除,而无需在主题中进行任何的更改。
  • 观察者或主题没有绑定在一起,所以可以彼此独立使用。如果需要的话,观察者可以在任何地方重复使用。
  • 主题或观察者中的变化不会相互影响。由于两者都是独立的或松散耦合的,所以它们可以自由地做出自己的改变。

6.6 观察者模式:优点和缺点

6.6.1 观察者模式具有以下优点:

  • 它使得彼此交互的对象之间保持松耦合;
  • 它使得我们可以在无需对主题或观察者进行任何修改的情况下高效地发送数据到其他对象;
  • 可以随时添加/删除观察者

6.6.2 观察者模式的缺点:

  • 观察者接口必须由具体观察者实现,而这涉及继承。无法进行组合,因为观察者接口可以实例化;
  • 如果实现不当的话,观察者可能会增加复杂性,并导致性能降低;
  • 在软件应用程序中,通知有时可能是不可靠的,并导致竞争条件或不一致性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/223372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python GUI教程:轻松构建用户界面

大家好,从网络开发到数据科学,Python被广泛应用于各个领域。本文将探索Python内置的用于创建图形用户界面(GUI)的库:Tkinter。无论是初学者还是经验丰富的开发者,了解如何创建Python GUI都可以增强构建交互…

Axie Infinity 之后,Ronin 的潜力何在?

作者:stellafootprint.network 数据来源:Ronin Dashboard 备受欢迎的 Web3 游戏 Pixels 在 2023 年 10 月下旬从 Polygon 迁移到了专为游戏设计的区块链 Ronin。Pixels 此前作为 Polygon 上活跃用户(钱包数量)最多的 Web3 游戏&…

iPhone手机中备忘录如何改变字体颜色

作为一名iPhone用户,我经常使用手机备忘录来记录生活中的点点滴滴。这样,我的大脑就能从繁琐的记忆任务中解脱出来,专注于更重要的事情。 而且,我有一个特别的习惯,那就是使用不同颜色的字体来区分不同的备忘录。这样…

学习黑马vue

项目分析 项目下载地址:vue-admin-template-master: 学习黑马vue 项目下载后没有环境可参考我的篇文章,算是比较详细:vue安装与配置-CSDN博客 安装这两个插件可格式化代码,vscode这个软件是免费的,官网:…

2023-12-14 二叉树的最大深度和二叉树的最小深度以及完全二叉树的节点个数

二叉树的最大深度和二叉树的最小深度以及完全二叉树的节点个数 104. 二叉树的最大深度 思想:可以使用迭代法或者递归!使用递归更好,帮助理解递归思路!明确递归三部曲–①确定参数以及返回参数 ②递归结束条件 ③单层逻辑是怎么样…

更改Android Studio的.android和.gradle文件夹默认位置

一、首先关闭Android Studio, 二、目标位置新建文件夹 这一步,为了省去麻烦,我并没有直接在我的目标位置新建文件夹,而是把C盘下的.android和.gradle文件夹整个复制过来,和SDK都在同一目录下,感觉这样可以…

MySQL:从MySQL看主从架构高可用性实现

目录 1 主备延迟 1.1 主备延迟 1.2 主备延迟的来源 1.2.1 主备机性能有差距 1.2.2 备库压力大 1.2.3 大事务 1.3 主备延迟的排查思路 3)查看MySQL状态 2 主备切换策略 2.1 可靠性优先策略 2.2 可用性优先策略 2.3 常见切换技术 从进入互联网时代开始&a…

class083 动态规划中用观察优化枚举的技巧-下【算法】

class083 动态规划中用观察优化枚举的技巧-下【算法】 算法讲解083【必备】动态规划中用观察优化枚举的技巧-下 code1 1235. 规划兼职工作 // 规划兼职工作 // 你打算利用空闲时间来做兼职工作赚些零花钱,这里有n份兼职工作 // 每份工作预计从startTime[i]开始、e…

GaussDB如何创建和管理视图

GaussDB如何创建和管理视图 一、什么是视图 当用户对数据库中的一张或者多张表的某些字段的组合感兴趣,而又不想每次键入这些查询时,用户就可以定义一个视图,以便解决这个问题。 视图与基本表不同,不是物理上实际存在的&#x…

基于ssm的“游侠”旅游信息管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本“游侠”旅游信息管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的…

自动灭火贴哪个牌子好?看懂灭火贴原理应该这么选!

随着大家安全意识的增强,无论是日常生活还是工业生产,都可以看到灭火器的踪影。但是往往在火情中,人们很难第一时间发现危险并及时扑灭,或多或少会造成财产损失,甚至影响到生命安全。近几年,自动灭火贴应运…

第十五章 React使用UI(Ant Design)框架

一、专栏介绍 😆😆 欢迎加入本专栏!本专栏将引领您快速上手React,让我们一起放弃放弃的念头,开始学习之旅吧!我们将从搭建React项目开始,逐步深入讲解最核心的hooks,以及React路由、…

【论文翻译】Learning Deep Features for Discriminative Localization

原文:Learning Deep Features for Discriminative Localization 摘要 在这项工作中,我们重新审视了文献[13]中提出的全局平均池化层,并阐明了它如何明确地使卷积神经网络具有出色的定位能力,尽管该网络是在图像级标签上进行训练的…

排序算法:【冒泡排序】、逻辑运算符not用法、解释if not tag:

注意: 1、排序:将一组无序序列,调整为有序的序列。所谓有序,就是说,要么升序要么降序。 2、列表排序:将无序列表变成有序列表。 3、列表这个类里,内置排序方法:sort( )&#xff0…

Python实现图形的几何变换

一、能够提供对话框窗口,输入三角形的顶点坐标;或者,采用鼠标左键单击方式输入三角形的顶点坐标。 二、对输入的三角形顶点坐标进行五种基本几何变换: 对于平移变换,能够提供对话框窗口,输入平移向量&…

HashMap:理解Hash、底层实现与扩容机制

一、简单叙述 HashMap是Java中常用的一种数据结构,它以键值对的形式存储数据,具有高效的查找、插入和删除操作。本文将详细介绍HashMap的底层实现原理,包括哈希技术、底层数据结构和扩容机制,帮助读者深入理解HashMap的工作原理。…

Java IO 模型之 BIO、NIO、AIO 详解

目录 一. 前言 二. IO 模型 2.1. IO 模型分类 2.2. BIO、NIO、AIO 使用场景分析 2.3. NIO 和 BIO 的比较 三. BIO(同步阻塞) 3.1. BIO 编程流程 3.2. BIO 应用实例 3.3. 问题分析 四. NIO(同步非阻塞) 4.1. 基本介绍 …

Dubbo 3.x源码(13)—Dubbo服务发布导出源码(2)

基于Dubbo 3.1,详细介绍了Dubbo服务的发布与引用的源码。 此前我们学习了Dubbo 3.x源码(12)—Dubbo服务发布导出源码(1),也就是Dubbo服务发布导出的入口源码,现在我们继续学习,服务导出的核心方法doExportUrls的源码。 Dubbo 3.x…

一文读懂Java中的设计模式——单例模式!默认情况下,Spring的Bean就是单例的

单例模式概念 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。单例模式只应在有真正的“单一实例”的需求时才可使用。总结起来单例模式有三个优点: 全局访问共享资源:当需要在应用程序的多个地方共享和使用相…

跑代码中遇到的错误合集(持续更新)

1.TypeError: dropout(): argument ‘input‘ (position 1) must be Tensor, not str 原因:dropout函数接收到的参数是一个字典类型(需手动设置其不要返回字典类型) 解决步骤: 1.根据代码定位到dropout函数 2.定位到函数中的参数 3.对给dropout函数参数赋值的函数的…