(六) python观察者设计模式

news2024/11/26 14:53:39

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 观察者模式的缺点:

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

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

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

相关文章

BGP综合

1、使用PreVal策略,确保R4通过R2到达192.168.10.0/24。 2、使用AS_Path策略,确保R4迪过R3到达192.168.11.0/24。 3、配置MED策略,确保R4通过R3到达192.168.12.0/24。 4、使用Local Preference策略,确保R1通过R2到达192.168.1.0…

IntelliJ idea卡顿解决,我遇到的比较管用的方案

Setttings> Build, Execution,Deployment>Debugger> Data Views> Java 取消 Enable "toString()" object view; Speed up debugging in IntelliJ Yesterday, I observed painfully slow debugging in IntelliJ. Every step over or step in took almost…

近期Chrome浏览器 不知哪个版本升级后原先http强制跳转到https,导致服务端302强制跳转到http也没反应

关于Chrome更新http强制跳转到https解决方法 近期Chrome浏览器 不知哪个版本升级后原先http强制跳转到https,导致服务端302强制跳转到http也没反应一、F12检查加载的Response Headers中有没有Non-Authoritative-Reason二、找了资料后得到解决方案:三、找…

在阿里云国际上构建共享虚拟主机业务

我们需要3个ECS实例,1个RDS MySQL实例和2个域名。我将使用该域作为我的主域和辅助域。sarathy.infosarathy.site 以下架构图左侧所示的两个 ECS 实例将托管我们的主网站。一个ECS实例用于部署WHMCS,另一个实例用于部署WordPress。WordPress 和 WHMCS 都…

pytorch-mask-rcnn 官方

This is a Pytorch implementation 实现 of Mask R-CNN that is in large parts based on Matterports Mask_RCNN. Matterports repository is an implementation on Keras and TensorFlow. The following parts of the README are excerpts 摘录 from the Matterport README. …

Amazon CodeWhisperer 提供新的人工智能驱动型代码修复、IaC 支持以及与 Visual Studio 的集成...

Amazon CodeWhisperer 的人工智能(AI)驱动型代码修复和基础设施即代码(IaC)支持已正式推出。Amazon CodeWhisperer 是一款用于 IDE 和命令行的人工智能驱动型生产力工具,现已在 Visual Studio 中推出,提供预…

C# WPF上位机开发(简易图像处理软件)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 图像处理是工业生产重要的环节。不管是定位、测量、检测还是识别,图像处理在工业生产中扮演重要的角色。而c#由于自身快速开发的特点&a…

12.8 作业

1, 使用手动连接,将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中,在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中,在槽函数中判断ui界面上输入的账号是否为"admin"&#…

持续集成和持续交付

引言 CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续交付和持续部署。作为一种面向开发和运维团队的解决方案,CI/CD 主要针对在集成新代码时所引发的问题(亦称:“集成地狱”&#…

【后端学前端学习记录】第一天 css动画 内凹导航栏

1、学习信息 css动画 内凹导航栏_哔哩哔哩_bilibili 随便找的的视频&#xff0c;主要原因是在公司不方便有声音 2、源码 最终源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title…

Tabbar切换效果(vant)

route 是否开启路由模式 <template><div class"layout-page"><!-- 二级路由出口 --><router-view></router-view><van-tabbar route><van-tabbar-item to"/home">首页<!-- 图标切换为active是高亮 -->&…

Zabbix结合Grafana打造高逼格监控系统

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

8、操作符重载

友元 可以通过friend关键字&#xff0c;把一个全局函数、另一个类的成员函数或者另一个类整体&#xff0c;声明为授权类的友元友元拥有访问授权类任何非公有成员的特权友元声明可以出现在授权类的公有、私有或者保护等任何区域且不受访问控制限定符的约束友元不是成员&#xf…

Nginx按指定格式记录访问日志

今天突然想起来一个日志的一个东西,因为拉项目无意中看到了日志文件的一些东西,现在不经常做后端了,加上其他的一些原因吧.有时候有些问题也没想太多,马马虎虎就过了,后来想想还是要记录一下这方面的处理过程吧: 一般我们作为开发人员关注的日志只是在应用程序层面的,我们称它…

Hanlp自然语言处理如何再Spring Boot中使用

一、HanLP HanLP (Hankcs NLP) 是一个自然语言处理工具包&#xff0c;具有功能强大、性能高效、易于使用的特点。HanLP 主要支持中文文本处理&#xff0c;包括分词、词性标注、命名实体识别、依存句法分析、关键词提取、文本分类、情感分析等多种功能。 HanLP 可以在 Java、Py…

delphi/python 实现小红书xhs用户作品列表和图片/视频无水印解析

技术学习&#xff0c;请勿用与非法用途&#xff01;&#xff01;&#xff01; 成品图用户作品列表接口 /api/sns/web/v1/user_posted?num30&cursor&user_id642bf0850000000011022c4e&image_scenes http Get方式&#xff0c;请求头需要带上x-s x-t签名验证笔记明细…

二叉树的层序遍历[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你二叉树的根节点root&#xff0c;返回其节点值的 层序遍历 。&#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],…

【算法每日一练]-图论(保姆级教程篇12 tarjan篇)#POJ3352道路建设 #POJ2553图的底部 #POJ1236校园网络 #缩点

目录&#xff1a; 今天知识点 加边使得无向图图变成双连通图 找出度为0的强连通分量 加边使得有向图变成强连通图 将有向图转成DAG图进行dp POJ3352&#xff1a;道路建设 思路&#xff1a; POJ2553&#xff1a;图的底部 思路&#xff1a; POJ1236校园网络 思路&#x…

[ndss 2023]确保联邦敏感主题分类免受中毒攻击

Securing Federated Sensitive Topic Classification against Poisoning Attacks 摘要 我们提出了一种基于联邦学习 (FL) 的解决方案&#xff0c;用于构建能够检测包含敏感内容的 URL 的分布式分类器&#xff0c;即与健康、政治信仰、性取向等类别相关的内容。尽管这样的分类器…

docker:搭建私有仓库

文章目录 1、拉取镜像2、运行容器3、测试成功4、修改daemon.json5、重启docker 服务6、上传镜像到私有仓库6.1 标记某个镜像为私有仓库镜像6.2 上传镜像到私有仓库 其他注意项 1、拉取镜像 docker pull registry2、运行容器 docker run -di --nameregistry -p 5000:5000 regi…