设计模式之观察者(发布订阅)模式

news2024/12/23 14:34:56

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同事监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己
在这里插入图片描述

  class Program
    {
        static void Main(string[] args)
        {
            ConcreteSubject concreteSubject = new ConcreteSubject();

            concreteSubject.Attach(new ConcreteObserver(concreteSubject, "奶茶店"));
            concreteSubject.Attach(new ConcreteObserver(concreteSubject, "快餐店"));
            concreteSubject.Attach(new ConcreteObserver(concreteSubject, "花店"));

            concreteSubject.SubjectState = "顾客来了";
            concreteSubject.Notify();//消息通知
            Console.ReadLine();
        }
    }

    //抽象消息通知者,一般用一一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个容器里,每个消息通知者都可以联系任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象
    abstract class Subject
    {
        private IList<Observer> observers = new List<Observer>();//观察者列表

        //增加观察者
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }

        //移除观察者
        public void Detach(Observer observer)
        {
            observers.Remove(observer);
        }

        //将消息通知给所观察者
        public void Notify()
        {
            foreach (Observer o in observers)
            {
                o.Update();
            }
        }


    }

    //抽象观察者,是所有观察者的基类,在得到消息发布者的消息后,使用更新方法更新自己的状态
    abstract class Observer
    {
        public abstract void Update();
    }


    //具体消息通知者,继承自Subject的具体类,将有关状态存入具体观察者对象;在具体消息通知者内部状态改变的时候,给所有在容器中的观察者发布消息。
    class ConcreteSubject : Subject
    {
        private string subjectState;//消息通知者的具体消息

        //具体被观察者状态
        public string SubjectState
        {
            get { return subjectState; }
            set { subjectState = value; }
        }
    }


    //具体观察者,实现抽象观察者的接口,以便本身的状态与消息通知者的状态相协调
    class ConcreteObserver : Observer
    {
        private string name;
        private string observerState;
        private ConcreteSubject subject;

        public ConcreteObserver(ConcreteSubject subject, string name)
        {
            this.subject = subject;
            this.name = name;
        }

        public override void Update()
        {
            observerState = subject.SubjectState;
            Console.WriteLine("{0}的新状态是{1}",name,observerState);
        }

        public ConcreteSubject Subject
        {
            get { return subject; }
            set { subject = value; }
        }


    }

观察者模式主要解决的问题:当一个对象状态发生改变后给其他的对象通知

观察者的优点:
观察者和被观察者是抽象耦合的,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。

观察者的缺点:
1、如果一个被观察者对象有很多的直接或间接的观察者的话,消耗的时间会增加很多。

2、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅是知道被观察者发生变化,会有很一些不需要改变状态的观察者被迫发生状态改变。

3、如果观察者与被观察者之间有循环依赖,会造成陷入死循环中,导致系统崩溃。


观察者模式的变体—— 发布订阅模式

发布订阅模式需要引用到了事件与委托这个两种类型

委托
事件

订阅发布模式,发布者的消息发送者不会讲消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心和中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地发布它们给订阅者。

优点
1、支持简单的广播通信,当对象状态发生改变时,会自动通知已经订阅过的对象
2、发布者与订阅者耦合性降低,发布者只管发布一条消息后,订阅者只监听发布者的事件名,只要发布者的事件名不变,它不管发布者如何改变

缺点
1、创建订阅者需要消耗一定时间的内存
2、增加维护的难度

区别与联系
联系:
订阅发布是观察者模式的一种变种。
区别:
1、观察模式中观察者和被观察者是松耦合的关系、发布-订阅模式中完全不存在耦合。
2、观察模式中观察者与被观察者相互感知,发布-订阅模式中存在中间调度工厂。

class Program
    {
        static void Main(string[] args)
        {
            Client c1 = new Client();

            ObserverA a = new ObserverA("路北", c1);
            ObserverB b = new ObserverB("路南", c1);

            c1.Update += new Handler(a.Work);
            c1.Update += new Handler(b.Work);

            c1.SubjectState = "顾客";
            c1.Notify();
        }
    }


    interface Subject
    {
       public void  Notify();
        string SubjectState
        {
            get;
            set;
        }
    }



    delegate void Handler();//声明委托
    class Client : Subject
    {
        public event Handler Update;//声明Handler(事件处理程序)的委托事件Update方法

        private string action;

        public void Notify()//引发Update方法
        {
            Update();
        }

        public string SubjectState
        {
            get { return action; }
            set { action = value; }
        }

 
    }
    class ObserverA
    {
        private string name;
        private Subject subject;
        public ObserverA(string name, Subject subject)
        {
            this.name = name;
            this.subject = subject;
            
        }

        public void Work()
        {
            Console.WriteLine("{0}来了,{1}开始工作",subject.SubjectState,name);
        }
    }

    class ObserverB
    {
        private string name;
        private Subject subject;
        public ObserverB(string name, Subject subject)
        {
            this.name = name;
            this.subject = subject;

        }

        public void Work()
        {
            Console.WriteLine("{0}来了,{1}开始工作", subject.SubjectState, name);
        }
    }

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

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

相关文章

[管理与领导-101]:IT人对高情商的误解?什么是高情商?

目录 前言&#xff1a; 一、人的心理架构 1.1 心理的基本过程 1.2 心理架构 1.3 冰山模型 1.4 IT人不同角度看人的能力层次 二、什么是智商和专业技能 2.1 什么是智商 2.2 什么是专业技能&#xff1a;表层 2.3 IT技术人员的智商和专业技能的重要性 2.4 IT技术人员的…

H.264编码

1.为什么要对视频进行编码 视频是连续的图像序列&#xff0c;由连续的帧构成&#xff0c;一帧即为一幅图像&#xff0c;由于人眼的视觉暂留效应&#xff0c;当帧序列以一定的速率播放时&#xff0c;我们看到的就是动作连续的视频&#xff0c;这么多连续的图像数据如果不经过编码…

在python3上使用pyautogui模拟鼠标键盘操作删除垃圾邮件

在PyPI The Python Package Index网站上搜索pyautogui&#xff0c;可以看到最新版本python3可用&#xff0c;本机环境&#xff1a;win7 64位&#xff0c;python3.8.10。之前写过一篇python2的文章&#xff0c;参考用python使用pyautogui库实现按键精灵模拟鼠标键盘找图的功能_…

如何看待unity新的收费模式

Unity的由来&#xff1a; Unity 是一款跨平台的游戏引擎&#xff0c;由 Unity Technologies 公司开发和维护。Unity 的起源可以追溯到 2002 年&#xff0c;当时 Unity Technologies 创始人之一的 David Helgason 在丹麦创建了一个名为 Over the Edge Entertainment 的游戏开发…

GLTF编辑器教你区分自发光贴图和光照贴图

什么自发光贴图 自发光贴图&#xff08;Emissive Mapping&#xff09;是一种用于在计算机图形学中模拟自发光效果的技术。它可以将光源直接嵌入纹理贴图中&#xff0c;以模拟物体表面具有发光效果的材质。 传统的纹理贴图只能模拟物体表面的颜色和纹理&#xff0c;无法模拟物体…

【Unity3D赛车游戏制作】开始界面场景搭建

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

【计算机网络笔记二】网络层

IP 地址分类和子网掩码 IPv4 地址—简称 IP 地址&#xff0c;IP 地址由 32 位比特组成 IP地址现在由因特网名字和数字分配机构 ICANN&#xff08;Internet Corporation for Assigned Names and Numbers&#xff09;进行分配&#xff0c;IP地址的作用&#xff1a;用于网络寻址&…

基于Java的酒店管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

【pytest】 参数化@pytest.mark.parametrize

1.创建 test_parametrize.py 通过 pytest.mark.parametrize 方法设置参数 import pytestimport math#pytest参数化 pytest.mark.parametrize("base,exponent,expected", # 参数变量名称# 每个元组都是一条测试用例测试数据[(2,2,4),(3,3,9),(1,9,1),(0,9,0)],i…

为什么网络安全缺口很大,而招聘却很少?学网络安全真的没有前途吗?

2020年我国网络空间安全人才数量缺口超过了140万&#xff0c;就业人数却只有10多万&#xff0c;缺口高达了93%。这里就有人会问了&#xff1a; 1、网络安全行业为什么这么缺人&#xff1f; 2、明明人才那么稀缺&#xff0c;为什么招聘时招安全的人员却没有那么多呢&#xff1…

多线程进阶学习笔记

文章目录 多线程进阶学习前言1、线程的状态1.1 线程状态相关介绍1.2 状态切换演示示例一示例二示例三 2、线程池2.1 线程池的实现2.2 JDK中的线程池2.2.1 Executors2.2.2 ThreadPoolExecutor2.2.3 线程池的工作原理2.2.4 任务拒绝策略 3、volatile关键字3.1 可见性问题3.2 JMM3…

Learn Prompt-Prompt 高级技巧:HuggingGPT

HuggingGPT是一个 Agent 框架&#xff0c;利用 ChatGPT 作为任务规划器&#xff0c;根据每个模型的描述来选择 HuggingFace 平台上可用的模型&#xff0c;最后根据模型的执行结果生成总结性的响应。这个项目目前已在 Github 上开源&#xff0c;并且有一个非常酷的名字叫做 JARV…

【5G PHY】物理层逻辑和物理天线的映射

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

MQ - 01 消息队列发展史MQ通用架构

文章目录 导图PreMQ 发展史消息队列的发展脉络MQ选型考虑因素消息 和 流消息队列的架构和功能什么情况下会使用消息队列?架构和功能的基本概念架构层面的基本概念功能层面的基本概念4款主流消息队列的区别和建议对比图导图 Pre MQ - 闲聊MQ一二事儿

字符串的大小(补充)

字符串大小 strlen对char b[ ] { ‘a’,‘b’,‘c’};不知道 ’\0‘在哪里&#xff0c;读取的是一个字符串 #include <iostream> using namespace std; int main() {char a[] { "abcde" };char b[] { a,b,c};cout << sizeof(a)/sizeof(a[0]) <&l…

Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数

Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数 Python函数绘图与高等代数互融实例(二):闪点函数 Python函数绘图与高等代数互融实例(三):设置X|Y轴|网格线 Python函数绘图与高等代数互融实例(四):设置X|Y轴参考线|参考区域 Python函数绘图与高等代数互融实例(五…

运营商停止提供公网IP地址,如何远程访问网络服务?

前段时间&#xff0c;广州电信宣布自2023年10月1日起&#xff0c;将不再为新装宽带和双栈宽带的用户提供公网IPv4地址。其实&#xff0c;自去年开始&#xff0c;中国三大运营商的各地分公司都纷纷宣布停止提供公网IPv4地址&#xff0c;这一决策的理由也都是IPv4公网地址资源已经…

JavaScript混淆工具大比拼:JScrambler和JShaman哪个更胜一筹?

两款顶级JavaScript混淆工具测评&#xff1a;JScrambler和JShaman 出于JavaScript代码安全需求&#xff0c;JavaScript混淆已经被广泛使用。在这个领域中&#xff0c;有免费的小工具&#xff0c;也有专业、商业级的产品。 商业产品在功能强度、保护效果、稳定性等各方面都是全…

胶质层指数

声明 本文是学习GB-T 397-2022 商品煤质量 炼焦用煤. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件规定了炼焦用商品煤产品质量等级和技术要求、试验方法、检验规则、标识、运输及贮存。 本文件适用于生产、加工、储运、销售、使用…