C++设计模式——观察者模式

2023-11-03

观察者模式(Observer)

        观察者模式是目前应用最广、影响范围最大的模式之一,因为 Observer 的一个实例Model/View/Control( MVC) 结构在系统开发架构设计中有着很重要的地位和意义, MVC实现了业务逻辑和表示层的解耦。个人也认为 Observer 模式是软件开发过程中必须要掌握和使用的模式之一。在 MFC 中, Doc/View(文档视图结构)提供了实现 MVC 的框架结构。同样Qt中核心机制:信号和槽的实现也同样有观察者的影子。

        Observer 模式要解决的问题为: 建立一个一( Subject)对多( Observer) 的依赖关系, 并且做到当“一” 变化的时候, 依赖这个“一”的多也能够同步改变。Observer 模式也称为发布-订阅( publish-subscribe),目标就是通知的发布者,观察者则是通知的订阅者(接受通知)。 最常见的一个例子就是: 对同一组数据进行统计分析时候, 我们希望能够提供多种形式的表示(例如以表格进行统计显示、 柱状图统计显示、 百分比统计显示等)。这些表示都依赖于同一组数据, 我们当然需要当数据改变的时候, 所有的统计的显示都能够同时改变。Observer 模式就是解决了这一个问题。Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

观察者(Observer)模式典型的结构图如下:

        这里的目标 Subject 提供依赖于它的观察者 Observer 的注册( Attach) 和注销( Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作( Notify)。 观察者 Observer 则提供一个 Update 操作, 注意这里的 Observer 的 Update 操作并不在 Observer 改变了 Subject 目标状态的时候就对自己进行更新, 这个更新操作要延迟到 Subject 对象发出 Notify 通知所有Observer 进行修改(调用 Update)。

观察者模式结构

Subject(被观察者)

 被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。

ConcreteSubject

被观察者的具体实现。包含一些基本的属性状态及其他操作。

Observer(观察者)

接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。

ConcreteObserver

观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

观察者模式类封装

template <typename T>

class IObserver

{

        /* 更新观察者 */

        virtual void Update(const T &t) = 0;

        virtual ~IObserver(){}

};



template <typename T>

class CSubject

{

public:

        CSubject()

        {

        }



        CSubject(const CSubject<T>& oValue)

        {

                m_oObserverList = oValue.m_oObserverList;

        }



        virtual ~CSubject()

        {

                Clear();

        }



        /* 注册观察者 */

        qint32 Attach(IObserver<T> *pObserver)

        {

                if (NULL == pObserver)

                {

                        return COMMON_INVALIDPARAM;

                }



                typename std::list<IObserver<T> *>iterator it = std::find(m_oObserverList.begin(),                 m_oObserverList.end(), pObserver);



                if (it != m_oObserverList.end())

                {

                        return COMMON_ALREADY_EXIST;

                }

                m_oObserverList.push_back(pObserver);

                return COMMON_SUCCEED;

        }



        /* 注销观察者 */

        void Detatch(IObserver<T> *pObserver)

        {

                if (NULL == pObserver)

                {

                        return COMMON_INVALIDPARAM;

                }



                typename std::list<IObserver<T> *>iterator it = std::find(m_oObserverList.begin(),                 m_oObserverList.end(), pObserver);

                if (m_oObserverList.end() == it)

                {

                        return COMMON_NOTFOUND;

                }

                m_oObserverList.erase(it);

                return COMMON_SUCCEED;

        }



        /* 目标状态发生变化时,通知所有的观察者 */

        void Notify(const T &t)

        {

                typedef std::list<IObserver<T> *>::iterator it = m_oObserverList.begin();

                for (; it != m_oObserverList.end(); ++it)

                {

                        (*it)->Update(t);

                }

        }



        /* 从清空所有观察者 */

        void Clear()

        {

                m_oObserverList.clear();

        }

private:

        std::list<IObserver<T> *> m_oObserverList; /* 保存观察者的链表对象 */

};

应用场景

  • 侦听事件驱动程序设计中的外部事件
  • 侦听/监视某个对象的状态变化
  • 发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者

        适用于: 定义对象间一种一对多的依赖关系,使得每一个对象改变状态,则所有依赖于他们的对象都会得到通知。 使用场景:定义了一种一对多的关系,让多个观察对象(公司员工)同时监听一个主题对象(秘书),主题对象状态发生变化时,会通知所有的观察者,使它们能够更新自己。

应用实例

#include <iostream>

using namespace std;

#include "vector"

#include "string"



class Secretary;



//玩游戏的同事类(观察者)

class PlayserObserver

{

public:

PlayserObserver(string name, Secretary *secretary)

{

m_name = name;

m_secretary = secretary;

}

void update(string action)

{

cout << "观察者收到action:" << action << endl;

}

private:

string m_name;

Secretary *m_secretary;

};



//秘书类(主题对象,通知者)

class Secretary

{

public:

void addObserver(PlayserObserver *o)

{

     v.push_back(o);

}

void Notify(string action)

{

     for (vector<PlayserObserver *>::iterator it= v.begin(); it!=v.end(); it++ )

{

(*it)->update(action);

}

}

void setAction(string action)

{

m_action = action;

Notify(m_action);

}

private:

string m_action;

vector<PlayserObserver *> v;

};



void main()

{

//subject 被观察者

Secretary *s1 = new Secretary;



//具体的观察者 被通知对象

PlayserObserver *po1 = new PlayserObserver("小张", s1);

//PlayserObserver *po2 = new PlayserObserver("小李", s1);

s1->addObserver(po1);

//s1->addObserver(po2);

s1->setAction("老板来了");

s1->setAction("老板走了");

cout<<"hello..."<<endl;

system("pause");

return ;

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++设计模式——观察者模式 的相关文章

  • 如何在MVVM中管理多个窗口

    我知道有几个与此类似的问题 但我还没有找到明确的答案 我正在尝试深入研究 MVVM 并尽可能保持纯粹 但不确定如何在坚持模式的同时启动 关闭窗口 我最初的想法是向 ViewModel 发送数据绑定命令 触发代码来启动一个新视图 然后通过 X
  • 将数组向左或向右旋转一定数量的位置,复杂度为 o(n)

    我想编写一个程序 根据用户的输入 正 gt 负 include
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • 如何忽略“有符号和无符号整数表达式之间的比较”?

    谁能告诉我必须使用哪个标志才能使 gcc 忽略 有符号和无符号整数表达式之间的比较 警告消息 gcc Wno sign compare 但你确实应该修复它警告你的比较
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • 如果使用 SingleOrDefault() 并在数字列表中搜索不在列表中的数字,如何返回 null?

    使用查询正数列表时SingleOrDefault 当在列表中找不到数字时 如何返回 null 或像 1 这样的自定义值 而不是类型的默认值 在本例中为 0 你可以使用 var first theIntegers Cast
  • Qt moc 在头文件中实现?

    是否可以告诉 Qt MOC 我想声明该类并在单个文件中实现它 而不是将它们拆分为 h 和 cpp 文件 如果要在 cpp 文件中声明并实现 QObject 子类 则必须手动包含 moc 文件 例如 文件main cpp struct Sub
  • 从路径中获取文件夹名称

    我有一些路c server folderName1 another name something another folder 我如何从那里提取最后一个文件夹名称 我尝试了几件事 但没有成功 我只是不想寻找最后的 然后就去休息了 Thank
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • Github Action 在运行可执行文件时卡住

    我正在尝试设置运行google tests on a C repository using Github Actions正在运行的Windows Latest 构建过程完成 但是当运行测试时 它被卡住并且不执行从生成的可执行文件Visual
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • 将 unsigned char * (uint8_t *) 转换为 const char *

    我有一个带有 uint8 t 参数的函数 uint8 t ihex decode uint8 t in size t len uint8 t out uint8 t i hn ln for i 0 i lt len i 2 hn in i
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce
  • C 中的异或运算符

    在进行按位操作时 我在确定何时使用 XOR 运算符时遇到一些困难 按位与和或非常简单 当您想要屏蔽位时 请使用按位 AND 常见用例是 IP 寻址和子网掩码 当您想要打开位时 请使用包含或 然而 XOR 总是让我明白 我觉得如果在面试中被问
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框
  • 恢复上传文件控制

    我确实阅读了以下帖子 C 暂停 恢复上传 https stackoverflow com questions 1048330 pause resume upload in c 使用 HTTP 恢复上传 https stackoverflow

随机推荐

  • VUE for循环 默认选中第一条数据

    for循环渲染列表默认选中第一条数据 点击其他选项切换数据 div div class Subtitle style padding 5px 40px 项目清单 div div class project manifest div clas
  • 【MySQL进阶】SQL性能分析

    一 SQL性能分析 1 SQL执行频率 MySQL 客户端连接成功后 通过 show session global status 命令可以提供服务器状态信 息 通过如下指令 可以查看当前数据库的 INSERT UPDATE DELETE S
  • Linux安装MySQL 5.7

    一 下载MySQL 官网地址 下载 mysql 5 7 37 linux glibc2 12 x86 64 tar gz 二 安装MySQL 1 1 连接Shell cd usr local 切换到此目录下 1 2 把MySQL包传到she
  • FPGA学习笔记4 --modesim软件仿真

    modesim软件仿真 一 手动仿真 二 联合仿真 一 手动仿真 1 添加路径 2 新建工程 3 添加源文件 4 编译文件 5 启动仿真 6 信号添加到波形里 7 运行 二 联合仿真 1 首先电脑要安装ModelSim软件 注意安装路径不要
  • Neo4j 快速入门

    Neo4j 快速入门 neo4j 官方文档 https neo4j com docs neo4j 中文社区 http neo4j com cn neo4j 开发者页面 https neo4j com developer Neo4j安装 a
  • 计算机键盘正确指法,键盘指法,详细教您盲打及快速打字指法练习的步骤

    有些人在用电脑打字的时候 会打的特别快 最快的时候能够一分钟打上八九十个字 而这样的打字速度也是靠平时的练就打字功力得来的 那么键盘指法打字如何才能将字打的准备又快呢 别着急 小编现在就来给你们普及一下这方面的知识 学会正确的键盘指法打字
  • 1.2 编程语言选择

    1 2 编程语言和城市选择 商业网站开发课 编程语言选择 后端开发语言 特点 排名网站 https hellogithub com report tiobe 薪资 参考2022年智联招聘 深圳初级和中级薪资 通用技能 操作系统 Linux
  • 在网络安全解决方案中使用数据挖掘技术

    网络安全 英语 network security 包含网络设备安全 网络信息安全 网络软件安全 黑客通过基于网络的入侵来达到窃取敏感信息的目的 也有人以基于网络的攻击见长 被人收买通过网络来攻击商业竞争对手企业 造成网络企业无法正常营运 网
  • 【ChatGPT实战案例】Excel代码太多记不住怎么办?ChatGPT来帮你高效解决问题

    目录 适合人群 使用工具 制作步骤 示例1 Excel数据分列 示例2 Excel数据提取 适合人群 会Excel基本操作 但是不懂Excel公式编写的人 使用工具 内容生产工具 如ChatGPT 讯飞星火认知模型 文心一言等 EXCEL文
  • LeetCode1748. 唯一元素的和(python)

    题目 给你一个整数数组 nums 数组中唯一元素是那些只出现 恰好一次 的元素 请你返回 nums 中唯一元素的 和 示例 1 输入 nums 1 2 3 2 输出 4 解释 唯一元素为 1 3 和为 4 示例 2 输入 nums 1 1
  • VCF变异文件读取和详细

    下载了千人基因组variants数据 是 vcf gz和 vcf gz tbi文件格式 需要在linux上打开 此时我还是一个生信小菜鸡 记录一下vcf文件读取和详细解释 在服务器先解压再打开 gunzip 文件 vcf gz cat 文件
  • 弹性盒模型学习

    一 弹性盒布局 1 弹性盒布局的容器指的是采用了弹性布局的DOM元素 而弹性布局的条目指的是容器中包含的子DOM元素 最外围的边框表示的是容器 而编号1和2的边框表示的是容器中的条目 弹性盒布局中有两个相互垂直的坐标轴 一个是主轴 另一个称
  • 【UE虚幻引擎】UE源码版编译、Andorid配置、打包

    首先是要下载源码版的UE 我这里下载的是5 2 1 首先要安装Git 在你准备放代码的文件夹下右键点击Git Bash Here 然后可以直接git clone https github com EpicGames UnrealEngine
  • 51单片机播放音乐(一):蜂鸣器

    51单片机播放音乐 一 蜂鸣器 原理 蜂鸣器 乐谱转成循环次数 单片机代码 仿真电路图 本文完整源码 原理 蜂鸣器 蜂鸣器分为有 震动 源的和无源的 有源的无法控制频率 所以用无源的才能播放音乐 无源蜂鸣器需要自己控制输入变化的信号才能发声
  • Rstudio MarkDown使用教程

    认识MarkDown MarkDown是一种轻量级的 标记语言 它的优点很多 目前也被越来越多的写作爱好者 撰稿者广泛使用 Markdown 的语法十分简单 常用的标记符号也不超过十个 对于大学里掌握了多门语言的我们来说 这种不需要思维 仅
  • R语言—如何下载和使用包

    R语言中有非常多的包 每个包都具有不同的功能 因此 在正式的R语言学习之前 需要学会如何下载和安装R的包 以此进行下一步学习 install packages 安装 1 打开RStudio软件 在RStudio中输入代码install pa
  • 实现增删查改

    核心代码 增 myModel Table1 Add data 删 myModel Table1 Remove data 查 var data myModel Table1 ToList 改 myModel Entry data State
  • js 随机获取数组几个内容

    function getRandomArrayElements arr count var shuffled arr slice 0 i arr length min i count temp index while i gt min in
  • HTML <textarea> 标签

    实例
  • C++设计模式——观察者模式

    观察者模式 Observer 观察者模式是目前应用最广 影响范围最大的模式之一 因为 Observer 的一个实例Model View Control MVC 结构在系统开发架构设计中有着很重要的地位和意义 MVC实现了业务逻辑和表示层的解