Observer(观察者模式)

1. 意图

        定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

        在观察者模式中,有两类对象:被观察者(Subject)和观察者(Observer)。被观察者是一个具有状态的对象,当其状态发生变化时,会通知所有的观察者。观察者是一个依赖于被观察者的对象,它会接收到被观察者的通知,并进行相应的处理。

2. 适用性

        《GOF设计模式:可复用面向对象软件的基础》中描述如下:

  • 当一个抽象模型有两方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们各自独立地自主改变和复用。
  • 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。
  • 当一个对象必须通知其它对象,而它又不能假定对象是谁。即对象之间关系是解耦合的。

3. 实现

#include <iostream>
#include <string>
#include <vector>class Observer {
public:virtual ~Observer() {}virtual void Update(const std::string &msg) = 0;
};class NetObserver : public Observer {
public:virtual void Update(const std::string &msg) override {std::cout << "NetObserver recv msg: " << msg << std::endl;}
};class SerialObserver : public Observer {
public:virtual void Update(const std::string &msg) override {std::cout << "SerialObserver recv msg: " << msg << std::endl;}
};class Subject {
public:virtual ~Subject() {}bool Attach(Observer *ptr) {if (ptr == nullptr)return false;m_vecObserver.push_back(ptr);return true;}void Detach(const Observer *ptr) {for (auto iter = m_vecObserver.begin(); iter != m_vecObserver.end();++iter) {if (*iter != ptr)continue;m_vecObserver.erase(iter);}}void Notify(const std::string &msg) {for (Observer *ptr : m_vecObserver)ptr->Update(msg);}private:std::vector<Observer *> m_vecObserver;
};class NetSubject : public Subject {
public:void DoSomething() { Notify("NetSubject msg"); }
};class SerialSubject : public Subject {
public:void DoSomething() { Notify("SerialSubject msg"); }
};void Test() {NetObserver *net1 = new NetObserver;NetObserver *net2 = new NetObserver;SerialObserver *serial1 = new SerialObserver;SerialObserver *serial2 = new SerialObserver;NetSubject *netSub = new NetSubject;SerialSubject *serialSub = new SerialSubject;netSub->Attach(net1);netSub->DoSomething();std::cout << "------------------------------" << std::endl;netSub->Attach(net2);netSub->DoSomething();std::cout << "------------------------------" << std::endl;serialSub->Attach(serial1);serialSub->DoSomething();std::cout << "------------------------------" << std::endl;serialSub->Attach(serial2);serialSub->DoSomething();delete net1;delete net2;delete serial1;delete serial2;delete netSub;delete serialSub;
}int main() {Test();return 0;
}

执行结果

NetObserver recv msg: NetSubject msg
------------------------------
NetObserver recv msg: NetSubject msg
NetObserver recv msg: NetSubject msg
------------------------------
SerialObserver recv msg: SerialSubject msg
------------------------------
SerialObserver recv msg: SerialSubject msg
SerialObserver recv msg: SerialSubject msg

4. 优缺点

  • 松耦合性:被观察者和观察者之间是松耦合的,它们之间仅通过接口或抽象类进行通信,不需要直接相互引用,可以独立变化。

  • 可扩展性:可以随时增加新的观察者,而不需要修改被观察者的代码,也可以很容易地添加新的被观察者。

  • 可重用性:观察者模式可以在不同的场景中重复使用,不需要重写逻辑。

  • 实时更新:被观察者一旦发生变化,所有的观察者都会实时收到通知并进行相应的更新,保证了数据的实时性。

  • 观察者过多:如果观察者的数量过多,通知所有观察者可能会导致性能问题,影响系统的运行效率。

  • 顺序控制困难:观察者之间是一种松散的耦合关系,无法控制观察者接收通知的顺序,可能会导致一些不可预测的问题。

  • 循环依赖问题:如果观察者与被观察者之间存在循环依赖,可能会导致系统出现问题。

5. 模板实现

#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>class ObserverA {
public:void UpdateA(const std::string &msg) {std::cout << "ObserverA msg: " << msg << std::endl;}
};class ObserverB {
public:void UpdateB(const std::string &msg) {std::cout << "ObserverB msg: " << msg << std::endl;}
};template <typename Func> class Event {
public:Event() : m_observeId(0) {}virtual ~Event() {}int Attach(Func &&f) { return Assign(f); }int Attach(const Func &f) { return Assign(f); }void Detach(int key) { m_mapOberserve.erase(key); }template <typename... Args> void Notify(Args &&...args) {for (auto &it : m_mapOberserve) {it.second(std::forward<Args>(args)...);}}private:Event(const Event &) = delete;Event &operator=(const Event &) = delete;template <typename F> int Assign(F &&f) {m_mapOberserve.emplace(m_observeId++, std::forward<F>(f));return m_observeId - 1;}private:int m_observeId;std::unordered_map<int, Func> m_mapOberserve;
};
void Test() {Event<std::function<void(const std::string &)>> event;ObserverA oba;int key =event.Attach(std::bind(&ObserverA::UpdateA, oba, std::placeholders::_1));event.Notify("AAAAA");std::cout << "-----------------------" << std::endl;ObserverB obb;event.Attach(std::bind(&ObserverB::UpdateB, obb, std::placeholders::_1));event.Notify("AAAAABBBBB");std::cout << "-----------------------" << std::endl;event.Detach(key);event.Notify("BBBBB");
}int main() {Test();return 0;
}

执行输出

ObserverA msg: AAAAA
-----------------------
ObserverB msg: AAAAABBBBB
ObserverA msg: AAAAABBBBB
-----------------------
ObserverB msg: BBBBB

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

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

相关文章

单片机原理与技术

文章目录 一、单片机概述二、单片机的基本原理1. **硬件结构**2. **指令系统** 三、单片机的关键技术1. **编程技术**2. **接口技术**3. **嵌入式系统技术** 四、单片机在现代科技中的应用 一、单片机概述 单片机&#xff0c;全称为单片微型计算机&#xff08;Single-Chip Mic…

Vue 路由设置

为了防止遗忘&#xff0c;记录一下用Vue写前端配置路由时的过程&#xff0c;方便后续再需要用到时回忆。 一、举个例子 假如需要实现这样的界面逻辑&#xff1a; 在HomePage中有一组选项卡按钮用于导航到子页面&#xff0c;而子页面Page1中有一个按钮&#xff0c;其响应事件是…

笔记-stm32移植ucos

文章目录 一、UCOS的基础知识1.1 前后台系统:1.2 RTOS系统可剥夺型内核:前后台系统和RTOS系统 1.3 UCOS系统简介学习方法 二、ucossii移植Step1&#xff1a;在工程中建立存放UCOSS代码的文件夹UCOSIIStep2:向CORE文件夹添加文件Step3:向Config文件夹添加文件Step4:向port文件夹…

LLM4Rec最新工作: 字节发布用于序列推荐的分层大模型HLLM

前几个月 Meta HSTU 点燃各大厂商对 LLM4Rec 的热情&#xff0c;一时间&#xff0c;探索推荐领域的 Scaling Law、实现推荐的 ChatGPT 时刻、取代传统推荐模型等一系列话题让人兴奋&#xff0c;然而理想有多丰满&#xff0c;现实就有多骨感&#xff0c;尚未有业界公开真正复刻 …

后端复习资料

后端面试资料 语雀-图灵面试题 语雀-javaGuide 小林coding&#xff1a;https://www.xiaolincoding.com/ 面试鸭&#xff1a; https://www.mianshiya.com/ codehot香菜哥&#xff1a;https://codehot.cn/markdown/welfare 面试题&#xff1a; vizard自行整理 牛客Golang社招面…

vscode中配置python虚拟环境

python虚拟环境作用 Python虚拟环境允许你为每个独立的项目创建一个隔离的环境&#xff0c;这样每个项目都可以拥有自己的一套Python安装包和依赖&#xff0c;不会互相影响。实际使用中&#xff0c;可以在vscode或pycharm中使用虚拟环境。 1.创建虚拟环境的方法&#xff1a; …

【NLP自然语言处理】01-基础学习路径简介

目的&#xff1a;让大家能够在 AI-NLP 领域由基础到入门具体安排&#xff1a; NLP介绍 文本预处理RNN 及其变体&#xff08;涉及案例&#xff09;Transformer 原理详解迁移学习 和 Bert 模型详解 &#xff08;涉及案例&#xff09;特点&#xff1a; 原理 实践每个文章会有练习…

04-SpringBootWeb案例(中)

3. 员工管理 完成了部门管理的功能开发之后&#xff0c;我们进入到下一环节员工管理功能的开发。 基于以上原型&#xff0c;我们可以把员工管理功能分为&#xff1a; 分页查询&#xff08;今天完成&#xff09;带条件的分页查询&#xff08;今天完成&#xff09;删除员工&am…

算法题总结(十)——二叉树上

#二叉树的递归遍历 // 前序遍历递归LC144_二叉树的前序遍历 class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result new ArrayList<Integer>(); //也可以把result 作为全局变量&#xff0c;只需要一个函数即可。…

Linus Torvalds 要求内核开发人员编写更好的 Git 合并提交信息

昨天在宣布 Linux 6.12-rc2 内核时&#xff0c;Linus Torvalds 要求内核维护者在提交信息方面做得更好。Torvalds 尤其希望内核维护者在描述拉取请求中的变更时&#xff0c;能更好地使用积极、命令式的语气。 Linux创建者在6.12-rc2 公告中解释道&#xff1a; 总之&#xff0c…

论文阅读笔记-XLNet: Generalized Autoregressive Pretraining for Language Understanding

前言 Google发布的XLNet在问答、文本分类、自然语言理解等任务上都大幅超越BERT,XLNet提出一个框架来连接语言建模方法和预训练方法。我们所熟悉的BERT是denoising autoencoding模型,最大的亮点就是能够获取上下文相关的双向特征表示,所以相对于标准语言模型(自回归)的预…

数据结构-基于不同策略的英文单词的词频统计和检索系统

数据结构课程设计:基于不同策略的英文单词的词频统计和检索系统 - 海月CSDN - 博客园 数据结构-基于不同策略的英文单词的词频统计和检索系统-CSDN博客 李冬梅老师课程设计 多学多练习!!!! C/C++在线餐馆预订管理系统_数据结构美团餐馆预订管理信息系统-CSDN博客 高校…

Java之Native详解

在Java编程中&#xff0c;Native方法是一种特殊的方法&#xff0c;它允许Java代码直接调用用其他编程语言&#xff08;如C或C&#xff09;编写的代码。这种机制使得Java程序能够与底层系统资源或其他编程语言进行交互&#xff0c;实现更高效的操作或访问特定功能。本文将详细介…

计算机科学各种协议

tls&#xff1a;TLS” 即 “Transport Layer Security”&#xff08;传输层安全&#xff09; ssl&#xff1a;SSL&#xff08;Secure Sockets Layer&#xff0c;安全套接层&#xff09;协议 Qos&#xff1a;网络服务质量&#xff08;Quality of Service&#xff0c;QoS&#…

前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比

这篇属于番外&#xff0c;属于技术性的讨论文&#xff0c;主要谈一下可能困惑不少人的问题。meteor看似一个前后端混合的框架&#xff0c;但实际上它并不是前后端混合的&#xff0c;只是共享了一个数据结构&#xff08;数据对象&#xff09;。现实中很多团队都说是前后端分离的…

【AIGC】ChatGPT提示词Prompt高效编写模式:结构化Prompt、提示词生成器与单样本/少样本提示

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;结构化Prompt (Structured Prompt)组成元素应用实例优势结论 &#x1f4af;提示词生成器 (Prompt Creator)如何工作应用实例优势结论 &#x1f4af;单样本/少样本提示 (O…

什么是安全运营中心 SOC?

SOC 代表安全运营中心&#xff0c;它是任何企业中负责组织安全、保护企业免受网络风险的单一、集中的团队或职能。 安全运营中心将管理和控制业务运营的所有安全要素&#xff0c;从监控资产到雇用合适的人员和流程&#xff0c;再到检测和应对威胁。 在本文中&#xff0c;我们…

PHP变量(第④篇)

本栏目教学是php零基础到精通&#xff0c;如果你还没有安装php开发工具请查看下方链接&#xff1a; Vscode、小皮面板安装-CSDN博客 今天来讲一讲php中的变量&#xff0c;变量是用于存储信息的"容器"&#xff0c;这些数据可以在程序执行期间被修改&#xff08;即其…

ThinkBook 16+ 锐龙6800h 安装ubuntu键盘失灵

问题&#xff1a;在ThinkBook 16 锐龙6800h 安装ubuntu18.04 出现笔记本键盘按下延迟非常高&#xff0c;输出卡死的情况&#xff0c;但是外接键盘可以正常使用 解决&#xff1a;更新内核 1、进入 https://kernel.ubuntu.com/~kernel-ppa/mainline/ 下载所需内核版本&#x…

Node.js+Express毕设论文选题最新推荐题目和方向

目录 一、前言 二、毕设选题推荐 三、总结 四、附录&#xff08;手册、官网、资源教程等&#xff09; 1. Node.js 官方资源 2. Express 官方资源 3.安装方法 4 创建示例 一、前言 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;它允许开发者使用…