设计模式->观察者设计模式和订阅者发布者设计模式的区别

设计模式->观察者设计模式和订阅者发布者设计模式的区别

  • 一、先复习一下观察者设计模式的相关定义,优点,以及缺点
    • 1.定义
      • 观察者模式的三个典型例子
    • 2.优点
    • 3.缺点
    • 4.观察者设计模式的主要角色
    • 5.代码举例
      • 完整代码
  • 二、回答问题:观察者设计模式和订阅者发布者设计模式的区别

一、先复习一下观察者设计模式的相关定义,优点,以及缺点

1.定义

观察者模式是指多个对象存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象的状态都会得到通知并自动更新。
这种模式又叫订阅者/发布者模式(但是又与观察者略有不同,写在后面了)、模式-视图模式,他是 对象行为型模式。

观察者模式的三个典型例子

1.例子 一:
大家在学校上自习的时候,等老师走了有些人会玩手机、吃零食、交头接耳找隔壁妹妹聊天,但是被老师发现可就不好了,所以大家想了一个招:让坐在最后排的同学帮忙“放风”,老师一来就给大家一个手势通知大家,大家就继续装好好学生(放入北影教程)
这其实就是一个典型的观察者模式:
“放风”的同学是被观察者(目标)
玩手机、吃零食的同学是观察者,大家都在观察“放风”同学(目标)的手势,一旦老师来了,被观察者(目标)就会通知大家。
2.例子 二:
csdn博客订阅就是采用观察者模式:
当博主发表新文章的时候,即博主的状态改变了变化,那些订阅的读者就会收到通知,然后进行相应的动作,比如去查看文章或者一键三连。博主与读者之间就会存在一对多的依赖关系。
3.例子 三:
事件触发模型

2.优点

1) 降低了目标与观察者之前的耦合关系。
在观察者模式中,观察者对象和主题对象之间是直接的关联关系,但是主题对象并不知道观察者对象的具体实现,而是只知道它们实现了共同的接口或抽象类。这样,主题对象和观察者对象之间的依赖关系就非常松散,它们可以独立地进行修改和扩展,而不会对彼此产生太大的影响。

2)目标与观察者之前建立了一套触发机制。

3.缺点

1)目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
解释:如果目标对象的实现发生变化,可能会影响到观察者对象的实现。这种依赖关系虽然比较松散,但并没有完全解除。
由于观察者对象需要订阅目标对象的状态变化事件,因此它们之间可能会形成循环引用。例如,当一个目标对象的状态发生变化时,它需要通知所有的观察者对象,而某些观察者对象可能需要调用目标对象的方法来获取最新的状态信息。如果这些观察者对象持有目标对象的引用,就可能出现循环引用的情况,从而导致内存泄漏等问题。

所以,为了解决以上问题,订阅者/发布者模式应运而生,订阅者/发布者模式使用了事件通道为目标和观察者搭建一个桥梁。订阅者/发布者模式(Publish-Subscribe Pattern)的一个重要特点就是使用了事件通道(Event Channel)来解除发布者(Publisher)和订阅者(Subscriber)之间的直接依赖关系,从而避免了循环引用等问题。

2)当观察者对象很多时,目标通知观察者就会花费很多时间,影响程序的效率。

4.观察者设计模式的主要角色

1)抽象主题(Subject)角色:【基类】
也叫抽象目标类,他提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。

2)具体主题(Concrete Subject)角色:

3)抽象观察者(Observer)角色:【基类】

4)具体观察者(Concrete Observer)角色:

5.代码举例

// 抽象观察者(基类)
class Observer
{
public:Observer() {}virtual ~Observer() {}virtual void Update() {}
};
// 抽象博客(基类)
class Blog
{
public:Blog() {}virtual ~Blog() {}void Attach(Observer *observer) { m_observers.push_back(observer); } // 添加观察者void Remove(Observer *observer) { m_observers.remove(observer); }    // 移除观察者void Notify()                                                        // 通知观察者{list<Observer *>::iterator iter = m_observers.begin();//遍历观察者链表for (; iter != m_observers.end(); iter++)(*iter)->Update();}virtual void SetStatus(string s) { m_status = s; } // 设置状态virtual string GetStatus() { return m_status; }    // 获得状态
private:list<Observer *> m_observers; // 观察者链表
protected:string m_status; // 状态
};

以上是观察者和博客(目标/被观察者/发布者),定义了通用接口。
博客类主要完成了观察者的添加、移除、通知操作。

// 具体博客类
class BlogCSDN : public Blog
{
private:string m_name; // 博主名称
public:BlogCSDN(string name) : m_name(name) {}~BlogCSDN() {}void SetStatus(string s) { m_status = "CSDN通知 : " + m_name + s; } // 具体设置状态信息string GetStatus() { return m_status; }
};
// 具体观察者
class ObserverBlog : public Observer
{
private:string m_name; // 观察者名称Blog *m_blog;  // 观察的博客,当然以链表形式更好,就可以观察多个博客
public:ObserverBlog(string name, Blog *blog) : m_name(name), m_blog(blog) {}~ObserverBlog() {}void Update() // 获得更新状态{string status = m_blog->GetStatus();cout << m_name << "-------" << status << endl;}
};
// 测试案例
int main()
{Blog *blog = new BlogCSDN("萧炎");Observer *observer1 = new ObserverBlog("观察者:冰皇海波东", blog);blog->Attach(observer1);blog->SetStatus("发表博客<<设计模式C++实现15——观察者模式>>");blog->Notify();delete blog;delete observer1;return 0;
}

完整代码

#include <iostream>
#include <list>using namespace std;// 抽象观察者(基类)
class Observer
{
public:Observer() {}virtual ~Observer() {}virtual void Update() {}
};
// 抽象博客(基类)
class Blog
{
public:Blog() {}virtual ~Blog() {}void Attach(Observer *observer) { m_observers.push_back(observer); } // 添加观察者void Remove(Observer *observer) { m_observers.remove(observer); }    // 移除观察者void Notify()                                                        // 通知观察者{list<Observer *>::iterator iter = m_observers.begin();for (; iter != m_observers.end(); iter++)(*iter)->Update();}virtual void SetStatus(string s) { m_status = s; } // 设置状态virtual string GetStatus() { return m_status; }    // 获得状态
private:list<Observer *> m_observers; // 观察者链表
protected:string m_status; // 状态
};// 具体博客类
class BlogCSDN : public Blog
{
private:string m_name; // 博主名称
public:BlogCSDN(string name) : m_name(name) {}~BlogCSDN() {}void SetStatus(string s) { m_status = "CSDN通知 : " + m_name + s; } // 具体设置状态信息string GetStatus() { return m_status; }
};
// 具体观察者
class ObserverBlog : public Observer
{
private:string m_name; // 观察者名称Blog *m_blog;  // 观察的博客,当然以链表形式更好,就可以观察多个博客
public:ObserverBlog(string name, Blog *blog) : m_name(name), m_blog(blog) {}~ObserverBlog() {}void Update() // 获得更新状态{string status = m_blog->GetStatus();cout << m_name << "-------" << status << endl;}
};// 测试案例
int main()
{Blog *blog = new BlogCSDN("萧炎");Observer *observer1 = new ObserverBlog("观察者:冰皇海波东", blog);blog->Attach(observer1);blog->SetStatus("发表博客<<设计模式C++实现15——观察者模式>>");blog->Notify();delete blog;delete observer1;return 0;
}//观察者:冰皇海波东-------CSDN通知 : 萧炎发表博客<<设计模式C++实现15——观察者模式>>

二、回答问题:观察者设计模式和订阅者发布者设计模式的区别

这两种模式之间的主要区别可以参考下图:
在这里插入图片描述
可以这么回答:

  1. 在23种基本的设计模式并没有订阅-发布模式,如果非要说有什么区别的话,我认为,订阅者发布者设计模式是观察者模式的变体,它们大部分是一致的,有很多相似之处,但并不完全相同,具体的区别有如下几点:

  2. 观察者模式里只有两个角色:观察者和被观察者。
    而,对于订阅发布者模式而言,它则有三种角色:发布者、订阅者、调度器(第三者->事件通道(Event Channel))。

  3. 观察者(Observer)模式中,观察者(Observers)角色知道抽象主题(Subject)角色,同时 , 抽象主题(Subject)角色 还保留了 观察者(Observers)角色 的记录。
    然而,在发布者/订阅者中,发布者和订阅者不需要彼此了解。他们只是在消息队列或代理的帮助下进行通信。
    订阅者/发布者(Subscriber / Publisher)模式中,组件是松散耦合(即彼此之间的依赖关系比较少,它们可以独立地进行修改和扩展,而不会对彼此产生太大的影响。)的;相比Observer模式,订阅者发布者模式的耦合更低。

  4. 观察者模式主要以同步方式实现,即当某些事件发生时,Subject调用其所有观察者的适当方法。发布者/订阅者在大多情况下是异步方式(使用消息队列)

  5. 观察者模式需要在单个应用程序地址空间中实现。而订阅者/发布者模式更像是跨应用程序模式。

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

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

相关文章

雅迪渐进、小牛徐行,两轮电动车“尖子生”竞争加剧

配图来自Canva可画 2023年中旬&#xff0c;两轮电动车品牌陆续上新车&#xff0c;对外展示品牌实力和创新力。 5月9日&#xff0c;哈啰智能电动车发布“极智系列”三款搭载了哈啰图灵T30智能平台的新车&#xff1b;5月10日&#xff0c;九号公司发布全新设计的E系列电摩顶配车型…

设计模式-观察者模式

观察者模式 1、观察者模式简介2、具体实现 1、观察者模式简介 观察者(Observer)模式指在被观察者的状态发生变化时&#xff0c;系统基于事件驱动理论将其状态通知到订阅模式的观察者对象中&#xff0c;以完成状态的修改和事件的传播。这种模式有时又叫做发布-订阅模式或者模型-…

Spring关于@Configuration配置处理流程解析

Configuration配置处理流程解析 AnnotationConfigApplicationContext基于注解配置ApplicationContext启动刷新流程Spring关于Configuration解析处理流程那些年被忽略问题 AnnotationConfigApplicationContext基于注解配置 Spring通过上下文应用AnnotationConfigApplicationCon…

MySQL-SQL存储过程/触发器详解(下)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

启动spring boot项目时加载配置文件报错的问题

最近把电脑重置了一下&#xff0c;然后重新安装各种软件&#xff0c;从gitee拉去项目到本地运行时居然启动报错了 Failed to load property source from file:/D:/program/IdeaProjects/layui/target/classes/application.yml 这是加载配置文件的时候失败了&#xff0c;提示一堆…

Mybatis-Plus:实现自定义SQL

目录 1.简介 2.自定义SQL具体实现 2.1.注解SQL 2.2.Wrapper传参注解SQL 2.3.Wrapper传参xml文件SQL 2.4.正常传参XML文件SQL 3.总结 1.简介 Mybatis-Plus&#xff08;以下简称MBP&#xff09;的初衷是为了简化开发&#xff0c;而不建议开发者自己写SQL语句的&#xff1b…

华为云CodeArts TestPlan测试设计:守护产品开发质量之魂

华为产品质量的守护神 华为云CodeArts TestPlan测试设计是华为产品质量的守护神。华为云CodeArts TestPlan提供多维度测试设计模板、“需求-场景-测试点-测试用例” 四层测试分解设计能力&#xff0c;启发测试人员发散性思维&#xff0c;对项目环境、测试对象、质量标准、测试…

深入理解 Golang: Goroutine 协程

进程用来分配内存空间&#xff0c;是操作系统分配资源的最小单位&#xff1b;线程用来分配 CPU 时间&#xff0c;多个线程共享内存空间&#xff0c;是操作系统或 CPU 调度的最小单位&#xff1b;协程用来精细利用线程。协程就是将一段程序的运行状态打包&#xff0c;可以在线程…

java之路——带你了解Hibernate与基本过程

文章目录 前言一、Hibernate用来干嘛的二、Hibernate与mybatisHibernate的基本开发步骤 前言 Hibernate框架的发展可以追溯到2001年&#xff0c;它在过去的几年里获得了广泛的应用和持续的发展。 其中的发展演变&#xff1a; 初期版本&#xff08;2001-2006年&#xff09;&am…

css基础知识十:介绍一下CSS中的Grid网格布局?

一、是什么 Grid 布局即网格布局&#xff0c;是一个二维的布局方式&#xff0c;由纵横相交的两组网格线形成的框架性布局结构&#xff0c;能够同时处理行与列 擅长将一个页面划分为几个主要区域&#xff0c;以及定义这些区域的大小、位置、层次等关系 这与之前讲到的flex一维…

【单片机】STM32F103C8T6 最小系统板原理图

STM32F103C8T6是一款基于ARM Cortex-M3内核的32位微控制器&#xff0c;由STMicroelectronics&#xff08;ST&#xff09;公司生产。它是STMicroelectronics的STM32系列微控制器中的一员&#xff0c;被广泛应用于嵌入式系统和电子设备中。 STM32F103C8T6单片机的主要特点和资源…

Windows11安装oneAPI和Visual Studio 2022配置Fortran并行环境

Windows11安装oneAPI和Visual Studio 2022配置Fortran并行环境 安装Visual Studio 2022 Community安装oneAPI建立Fortran工程项目测试建立单核运行的Fortran运行算例建立并行运行的Fortran运行算例 结语 安装Visual Studio 2022 Community 访问微软Visual Studio官网&#xff…