(六) 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 = None

    def 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 = news

    def getNews(self):
        # 返回新消息
        return "获取到消息:", self.latestNews


from abc import ABCMeta, abstractmethod


class Subscriber(metaclass=ABCMeta):
    """
    观察者抽象基类,具体观察者继承该类,并实现抽象方法
    """
    @abstractmethod
    def update(self):
        # update()方法是由具体订阅者实现的,
        # 这样只要有新闻发布的时候它们都能得到 Subject(NewsPublishers)的相应通知。
        pass
class SMSSubscriber(Subscriber):
    """
    短信观察者
    """
    def __init__(self, publisher):
        # 初始化时进行注册
        self.publisher = publisher
        self.publisher.attach(self)

    def update(self):
        print(type(self).__name__, self.publisher.getNews())

class EmailSubscriber(Subscriber):
    """
    邮件观察者
    """
    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.attach(self)

    def update(self):
        print(type(self).__name__, self.publisher.getNews())

class AnyOtherSubscriber(Subscriber):
    # 其他观察者
    def __init__(self, publisher):
        self.publisher = publisher
        self.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 观察者模式的缺点:

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

echarts折线图的数据显示

一、 echarts让折线图的每个折点都显示y轴的数值 效果如下 // 在 series中添加 itemStyle : { normal: {label : {show: true}}}series: [{name: 买入汇率,data: BuyRate,type: line,itemStyle : { normal: {label : {show: true}}}},{name: 卖出汇率,data: SaleRate,type: lin…

仅需30秒完美复刻任何人的声音 - 最强AI音频11Labs

我的用词一直都挺克制的,基本不会用到“最强”这个字眼。 但是这一次的这个AI应用,是我认为在TTS(文字转音频)这个领域,当之无愧的“最强”。 ElevenLabs,简称11Labs。 仅需30秒到5分钟左右的极少的数据集…

Qt简介、工程文件分离、创建Qt工程、Qt的帮助文档

QT 简介 core:核心模块,非图形的接口类,为其它模块提供支持 gui:图形用户接口,qt5之前 widgets:图形界面相关的类模块 qt5之后的 database:数据库模块 network:网络模块 QT 特性 开…

土壤水分传感器土壤体积含水率含量监测仪器

产品概述 外型小巧轻便,便于携带和连接。 土壤水分传感器由电源模块、变送模块、漂零及温度补偿模块、数据处理模块等组成。传感器内置信号采样及放大、漂零及温度补偿功能,用户接口简洁、方便。 功能特点 ◆本传感器体积小巧化设计,测量…

Sam Altman当选“TIME时代周刊”2023年度最佳CEO!还有梅西、Taylor Swift当选...

TIME时代周刊昨日在官网公布了2023年最佳CEO—— Sam Altman当选! 此外,Taylor Swift当选年度最佳人物,梅西当选年度最佳运动员。 Sam Altman的当选可谓是实至名归!没有谁能比火爆全球的ChatGPT背后,OpenAI的CEO更“成功”了。 …

手把手教你写 Compose 动画 -- 讲的不能再细的 AnimationSpec 动画规范

前面我们聊过 animateDpAsState 和 Animatable 两种动画 API 的用法&#xff0c;但只是简单了解了&#xff0c;这两个函数内部都有一个共同的核心参数&#xff1a;AnimationSpec。 Composable fun animateDpAsState(targetValue: Dp,animationSpec: AnimationSpec<Dp> …

代码随想录算法训练营第45天| 70. 爬楼梯 (进阶) 322. 零钱兑换 279.完全平方数

JAVA代码编写 70. 爬楼梯&#xff08;进阶版) 卡码网&#xff1a;57. 爬楼梯&#xff08;第八期模拟笔试&#xff09; 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬至多m (1 < m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f…

卷王开启验证码后无法登陆问题解决

问题描述 使用 docker 部署&#xff0c;后台设置开启验证&#xff0c;重启服务器之后&#xff0c;docker重启&#xff0c;再次访问系统&#xff0c;验证码获取失败&#xff0c;导致无法进行验证&#xff0c;也就无法登陆系统。 如果不了解卷王的&#xff0c;可以去官网看下。…

【K8S】微服务不香了?单体化改造悄然兴起!!

微服务一直以来是服务治理的基本盘之一,落地到云原生上,往往是每个 K8s pods 部署一个服务,独立迭代、独立运维。 但是在快速部署的时候,有时候,我们可能需要一些宏服务的优势。有没有一种方法,能够 “既要又要” 呢?本文基于 tRPC-Go 服务,提出并最终实践了一种经验证…

医学图像数据处理流程以及遇到的问题

数据总目录&#xff1a; /home/bavon/datasets/wsi/hsil /home/bavon/datasets/wsi/lsil 1 规整文件命名以及xml拷贝 data_prepare.py 的 align_xml_svs 方法 if __name__ __main__: file_path "/home/bavon/datasets/wsi/lsil"# align_xml_svs(file_path) # b…

程序员的养生指南(生命诚可贵,一人永流传!珍惜生命,从你我做起)

作为程序员&#xff0c;我们经常需要长时间坐在电脑前工作&#xff0c;这对我们的身体健康造成了很大的影响。为了保持健康&#xff0c;我们需要采取一些养生措施来延寿。下面是我个人的一些养生经验和建议&#xff0c;希望能对大家有所帮助。 1、合理安排工作时间&#xff1a;…

Bert-vits2新版本V2.1英文模型本地训练以及中英文混合推理(mix)

中英文混合输出是文本转语音(TTS)项目中很常见的需求场景&#xff0c;尤其在技术文章或者技术视频领域里&#xff0c;其中文文本中一定会夹杂着海量的英文单词&#xff0c;我们当然不希望AI口播只会念中文&#xff0c;Bert-vits2老版本(2.0以下版本)并不支持英文训练和推理&…

多功能智能遥测终端机 5G/4G+北斗多信道 视频采集传输

计讯物联多功能智能遥测终端机&#xff0c;全网通5G/4G无线通信、弱信号地区北斗通信&#xff0c;多信道自动切换保障通信联通&#xff0c;丰富网络接口及行业应用接口&#xff0c;支持水利、环保、工业传感器、控制终端、智能终端接入&#xff0c;模拟量/数字量/信号量采集&am…

一文详解Java反射

文章目录 反射是什么&#xff1f;反射的作用所有方法汇总一、加载Class对象二、加载类的构造器对象三、加载类的成员变量四、加载类的成员方法 反射是什么&#xff1f; 反射就是&#xff1a;加载类&#xff0c;并允许以编程的方式解剖类中的某个成分&#xff08;成员变量&#…

ambari hive on Tez引擎一直卡住

hive on tez使用./bin/hive启动后一直卡住&#xff0c;无法进入命令行 使用TEZ作为Hive默认执行引擎时&#xff0c;需要在调用Hive CLI的时候启动YARN应用&#xff0c;预分配资源&#xff0c;这需要花一些时间&#xff0c;而使用MapReduce作为执行引擎时是在执行语句的时候才会…

微信小程序UI自动化测试实践:Minium+PageObject

小程序架构上分为渲染层和逻辑层&#xff0c;尽管各平台的运行环境十分相似&#xff0c;但是还是有些许的区别&#xff08;如下图&#xff09;&#xff0c;比如说JavaScript 语法和 API 支持不一致&#xff0c;WXSS 渲染表现也有不同&#xff0c;所以不论是手工测试&#xff0c…

Spingboot3详解(全网最详细,新建springboot项目并详解各种组件的用法)

一.Spring Initializr创建向导 1.新建一个空项目 2.在新创建的空项目里&#xff0c;新建Module 3. 选择Spring Initializr 4.选择Spring Boot的版本3以上 5.创建好的一个项目结构 controller包是自己创建的 6.项目结构分析 spingboot主程序 package com.example.boot;impor…

使用hutool工具生成非对称加密公私密钥以及使用案例

1.导入hutool依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version></dependency>2.直接复制代码 package com.common.utils;import cn.hutool.core.codec.Base64; i…

mac苹果电脑清除数据软件CleanMyMac X4.16

在数字时代&#xff0c;保护个人隐私变得越来越重要。当我们出售个人使用的电脑&#xff0c;亦或者离职后需要上交电脑&#xff0c;都需要对存留在电脑的个人信息做彻底的清除。随着越来越多的人选择使用苹果电脑&#xff0c;很多人想要了解苹果电脑清除数据要怎样做才是最彻底…

优秀软件测试工程师必备的“8个能力”

首先要说&#xff0c;做软件测试不难&#xff0c;难的是做好软件测试。 结合自己这些年的工作经验&#xff0c;自己也总结出来8个方面的能力&#xff0c;可能有些方面感觉要求暂时还达不到&#xff0c;但这些确实是做软件测试工作所必备的能力&#xff0c;掌握了这8个方面的能力…