【六】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都可以增强构建交互…

Makefile基本指令

语法规则 目标 ... : 依赖 ...命令1命令2. . .1、目标即要生成的文件。如果目标文件的更新时间晚于依赖文件更新时间,则说明依赖文件没有改动,目标文件不需要重新编译。否则会进行重新编译并更新目标文件。 2、默认情况下Makefile的第一个目标为终极目…

系统接口未找到报404异常统一返回处理

上篇博客:异常处理返回结构体,做到全局统一,仍然会出现一些情况。 针对未找到接口爆出404异常,返回结构体如果没有处理的话会变成下面这样,不会走全局异常处理,这样的话就没有完全做到全局异常统一处理。 …

es模板和索引简单操作简介

一、模板 1、创建模板 (1)请求url http://127.0.0.1:9201/_template/template_test (2)请求方式 PUT (3)请求体 { "index_patterns": ["test*"], "settings": { …

并发相关参数指标

指标 1、TPS和QPS 一、TPS:Transactions Per Second(每秒传输的事物处理个数),即服务器每秒处理的事务数。TPS包括一条消息入和一条消息出,加上一次用户数据库访问。(业务TPS CAPS 每个呼叫平均TPS&…

前端发送请求之参数处理---multipart/form-data与application/x-www-form-urlencoded

Content-Type就是指 HTTP 发送信息至服务器时的内容编码类型,服务器根据编码类型使用特定的解析方式,获取数据流中的数据。 其实前后端发送请求的方式有 text/plain、application/json、application/x-www-form-urlencoded、 multipart/form-data等&…

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这个软件是免费的,官网:…

什么是 Spring 框架?

Spring 框架是一个开源的、轻量级的企业级应用框架,用于构建 Java 应用程序。它提供了全面的基础设施支持,以简化企业级应用的开发。Spring 的核心目标是通过促进良好的设计原则和编程习惯来提高 Java 开发人员的效率和系统的可维护性。 Spring 框架的主…

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…

快速诊断试剂原料的快速诊断——博迈伦生物

快速诊断试剂在医学领域中发挥着至关重要的作用,其原料的选择直接关系到试剂的性能和准确性。在设计和制备快速诊断试剂时,必须仔细考虑原料的选择,以确保其在诊断过程中表现出色。以下是一些常见的快速诊断试剂原料及其特性的概述。 1. 抗体…

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

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

Python 字典:dic = {} 和 dic = defaultdict(list)之间的区别

d defaultdict(list) 和 d {} 在Python中代表了两种不同类型的字典初始化方式,它们之间有几个关键的区别: 1、类型 d defaultdict(list):这里使用的是 collections 模块中的 defaultdict 类。它是一个字典的子类,提供了一个默…

基于K-Means的图片聚类算法实战

一. 场景说明 我们通常遇到一个问题,当很多图片放在一个文件夹中,要把这些文件夹中的图片按规律分为几类。当图片比较少时,我们可以手动完成,但是当图片的数量是几千甚至几万时,手动挑选图片的工作量就太大了。 因此&…

git关于ssh我遇到的问题解决链接

新手,第一次用gitee上传程序,花了好几天(有空就弄)才搞定,刚开始弄https,但我的用户名和密码都不知道,网上找的办法都重置不了。下面是我弄ssh时遇到的问题 在gitee设置ssh公钥: G…

GaussDB如何创建和管理视图

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

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

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