C++观察者模式

article/2025/9/24 15:53:11

C++观察者模式

  当对象间存在一对多关系时,则使用观察者模式(observer pattern)。比如,当一个对象被修改时,则会自动通知发依赖它的对象。观察者模式属于行为型模式。

  Observer模式是应用最多、影响最广的设计模式之一,因为Observer的一个实例Model/View/Control(MVC)结构在系统开发架构设计中有着很重要的地位和意义,MVC实现了业务逻辑和表示层的解耦。在MFC(微软基础类库)中,Doc/View(文档视图结构)提供了实现MVC的框架结构。

  在GOF的《设计模式:可复用面向对象软件的基础》一书中对观察者模式是这样定义的:定义对象的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。当一个对象发生了变化,关注它的对象就会得到通知;这种交互也成为发布-订阅(publish-subscribe)。

   MVC框架是模型-视图-控制器的缩写,一种软件设计典范。用一种业务逻辑、数据、显示界面分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能。在一个逻辑的图形化用户界面的结构中MVC分层有助于管理复杂的应用程序,因为可以在一个时间内专注的关注一个方面,可以在不依赖业务逻辑的情况下专注于视图设计,同时也将应用程序的测试更加容易。

介绍

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

主要解决:一个对象状态改变并给其它对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:使用面向对象技术,可以将这种依赖关系弱化。

关键代码:在抽象类里有一个arrayList存放观察者们。

应用实例:1、拍卖的时候,拍卖师观察最高价格,然后通知给其它竞价者竞价。2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水找来一个老乌龟,这个老乌龟就是观察者(菩萨是被观察者),他观察菩萨这个动作。

优点:1、观察者和被观察者是抽象耦合的。2、建立一套触发机制。

缺点:1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景

  • 一个抽象模型有两个方面,其中一个方面发依赖于另外一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其它一个或多个对象发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

注意事项:1、应避免循环引用。2、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式(多线程)。

示例1

  对同一组数据进行统计分析的时候,我们希望能够提供多种形式的表示(例如以表格形式进行显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有统计的显示都能同时改变、Observer模式就是解决了这一个问题。

UML类图

效果图

  • Subject(目标)
    • 目标知道它的观察者,可以有任意多个观察者观察用一个目标。
    • 提供注册和删除观察者对象的接口。
  • Observer(观察者)
    • 为所有观察目标的观察者对象提供一个公共的更新接口。
  • ConcreteSubject(具体目标)
    • 将有关状态的情况广播给各ConcreteObserver对象。
  • ConcreteObserver(具体观察者)
    • 维护一个指向ConcreteSubject对象的指针。用于当具体观察者初始化时直接存入ConcreteSubject对象(初始化就订阅ConcreteSubject主题)。
    • 存储有有关状态,这些状态应与目标的状态保持一致。
    • 实现Observer公共更新接口以便使自身状态和目标状态保持一致。

观察者模式按照以下方式进行协作:

  1. 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
  2. 在得到一个具体目标的改变通知后,ConcreteObserver对象可收到目标对象的信息。ConcreteObserver使用这些信息使它的状态和目标对象的状态保持一致。

代码实现:

#include <iostream>
#include <list>
using std::cout;
using std::endl;
using std::cin;class Observer{public:virtual ~Observer() {};virtual void Update(int) = 0;};class Subject{public:virtual ~Subject() {};virtual void Attach(Observer*) = 0;virtual void Detach(Observer*) = 0;virtual void Notify() = 0;};class ConcreteObserver : public Observer{private:Subject *_pSubject;public:ConcreteObserver(Subject* pSubject) :_pSubject(pSubject){//在目标中注册当前观察者(此处的观察者是广义上的观察者,目标并不知道具体谁要观察它,目标只进行广播即可)this->_pSubject->Attach(this);cout << "I'm the observer \" 1 \".\n";}void Update(int value) override{cout << "ConcreteObserver get the update.New State:" << value << endl;}};class ConcreteObserver2 : public Observer{private:Subject *_pSubject;public:ConcreteObserver2(Subject* pSubject) :_pSubject(pSubject){//在目标中注册当前观察者(此处的观察者是广义上的观察者,目标并不知道具体谁要观察它,目标只进行广播即可)this->_pSubject->Attach(this);cout << "I'm the observer \" 2 \".\n";}void Update(int value) override{cout << "ConcreteObserver2 get the update.New State:" << value << endl;}};class ConcreteSubject :public Subject{private:std::list<Observer*> _pObserverList;int _iState;public:void SetState(int state){_iState = state;}void Attach(Observer* pObserver) override{_pObserverList.push_back(pObserver);}void Detach(Observer* pObserver) override{_pObserverList.remove(pObserver);}void Notify() override{auto begin = _pObserverList.begin();auto end = _pObserverList.end();while (begin != end){(*begin)->Update(_iState);begin++;}}};int main()
{//创建目标ConcreteSubject *pSubject = new ConcreteSubject();//创建观察者Observer *pObserver = new ConcreteObserver(pSubject);Observer *pObserver2 = new ConcreteObserver2(pSubject);//改变当前状态pSubject->SetState(2);//广播给所有广义上的观察者pSubject->Notify();//去除某个观察者pSubject->Detach(pObserver);//改变当前状态pSubject->SetState(3);//重新广播pSubject->Notify();//结束,释放对象delete pObserver;delete pObserver2;delete pSubject;return 0;
}

输出结果(vs2017):

效果图

示例2(高阶版)

#include <iostream>
#include <list>
#include <string>
using std::cout;
using std::endl;
using std::cin;/*
观察者模式有许多具有类似含有的不同术语,比如主题也成为发布者,观察者通常称为订阅者。
动词“观察”、“倾听”或“跟踪”通常表示相同的意思。
*/class IObserver
{
public:virtual ~IObserver() {}virtual void Update(const std::string &messageFromSubject) = 0;
};class ISubject
{
public:virtual ~ISubject() {}virtual void Attach(IObserver *observer) = 0;virtual void Detach(IObserver *observer) = 0;virtual void Notify() = 0;
};//具体目标拥有一些重要的状态,并在状态更改时通知观察者
class Subject : public ISubject
{
private:std::list<IObserver *> _listObserver;std::string _messgae;
public:virtual ~Subject(){cout << "Goodbye,I was the Subject.\n";}//定义订阅管理方法void Attach(IObserver* observer) override{_listObserver.push_back(observer);}void Detach(IObserver* observer) override{_listObserver.remove(observer);}void Notify() override{std::list<IObserver *>::iterator begin = _listObserver.begin();HowManyObserver();while (begin != _listObserver.end()){(*begin)->Update(_messgae);++begin;}}void CreateMessage(std::string message = "Empty"){this->_messgae = message;Notify();}void HowManyObserver(){cout << "There are " << _listObserver.size() << " observers in the list\n";}/*通常的来说,订阅逻辑知识主题真正能做的事情的一小部分。主题通常拥有一些重要的业务逻辑,每当重要的事情即将发生(或者发生之后)时触发通知方法。*/void SomeBusinessLogic(){this->_messgae = "change message message";Notify();cout << "I'm about to do some thing important.\n";}
};class Observer :public IObserver
{
private:std::string _messageFromSubject;Subject &_subject;static int _staticNumber;int _number;
public:Observer(Subject &subject) :_subject(subject){this->_subject.Attach(this);cout << "Hi,I'm the Observer \"" << ++Observer::_staticNumber << "\".\n";this->_number = Observer::_staticNumber;}~Observer(){cout << "Goodbye, I was the Observer \"" << this->_number << "\".\n";}void Update(const std::string &messageFromSubject) override{this->_messageFromSubject = messageFromSubject;PrintInfo();}void RemoveMeFromTheList(){this->_subject.Detach(this);cout << "Observer \"" << this->_number << "\" removed from the list.\n";}void PrintInfo(){cout << "Observer \"" << this->_number << "\": a new message is aviilable -->" << this->_messageFromSubject << "\n";}};int Observer::_staticNumber = 0;void ClientCode()
{Subject * subject = new Subject();Observer *observer1 = new Observer(*subject);Observer *observer2 = new Observer(*subject);Observer *observer3 = new Observer(*subject);Observer *observer4;Observer *observer5;subject->CreateMessage("hello world! :D");observer3->RemoveMeFromTheList();subject->CreateMessage("The weather is hot today! :p");observer4 = new Observer(*subject);observer2->RemoveMeFromTheList();observer5 = new Observer(*subject);observer4->RemoveMeFromTheList();observer1->RemoveMeFromTheList();delete observer5;delete observer4;delete observer3;delete observer2;delete observer1;delete subject;
}int main()
{ClientCode();return 0;
}

输出结果(vs2017):

效果图

参考文章

https://www.runoob.com/design-pattern/observer-pattern.html

https://www.cnblogs.com/carsonzhu/p/5770253.html


http://chatgpt.dhexx.cn/article/CinON1AC.shtml

相关文章

Android开发模式之观察者模式

目录 一、定义 1.观察者模式 2.UML类图 3.观察者模式中的角色 二、使用场景 三、简单实现 四、观察者模式在java.util包中的应用 五、观察者模式在Button中的应用 六、观察者模式在ListView中的应用 七、观察者模式的优缺点 观察者模式的优点 观察者模式的缺点 一、…

java设计模式-观察者模式

观察者模式介绍&#xff1a; 观察者模式&#xff08;有时又被称为发布/订阅模式&#xff09;是软件设计模式的一种。在此种模式中&#xff0c;一个目标对象管理所有相依于它的观察者对象&#xff0c;并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法…

观察者模式(Observer) 简介

一, 观察者模式(Observer) 的定义 观察者模式: 定义了一种 1对多 的依赖关系, 让多个观察者对象同时监听1个主题对象. 这个主题对象在状态发生变化时, 会通知所有的观察者对象, 使它们能够同时更新自己. 稍微解释一下 这个1 对多 的依赖关系. 1对多 这个关键词我们常常在DB …

观察者模式

第23章 观察者模式 一、观察者模式的基本介绍 观察者模式(Observer Pattern)&#xff1a;定义对象间的一种一对多依赖关系&#xff0c;使得每当一个对象状态发生改变时&#xff0c;其相关依赖对象皆得到通知并被自动更新。 观察者模式又叫做发布-订阅&#xff08;Publish/Subsc…

观察者模式(Observer Pattern)

一、什么是观察者模式 观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系&#xff0c;当一个对象(目标对象)的状态发生改变时&#xff0c;所有依赖于它的对象(观察对象)都得到通知并被自动更新。特点&#xff1a;被观察者和观察者一般是一对多的关系&#xf…

设计模式之观察者模式详解(附应用举例实现)

文章目录 1 观察者模式介绍2 观察者模式详解2.1 观察者模式结构2.2 观察者模式实现2.3 观察者模式应用举例 3 观察者模式与MVC 1 观察者模式介绍 “红灯停&#xff0c;绿灯行”。在这个过程中&#xff0c;交通信号灯是汽车的观察目标&#xff0c;而汽车则是观察者。随着交通信…

23种设计模式——观察者模式

目录 观察者模式&#xff08;Observer&#xff09; 理解 UML图 优缺点 观察者模式在各语言中的支持 Java C# 实例 小丑表演 办公室摸鱼 投资者与股票 观察者模式&#xff08;Observer&#xff09; 本质&#xff1a;触发联动 目标对象变化时&#xff0c;会通知所有登…

设计模式(五)观察者模式

相关文章 设计模式系列 1.观察者模式模式简介 定义 观察者模式&#xff08;又被称为发布-订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;属于行为型模式的一种&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对…

Win64 驱动内核编程-28.枚举消息钩子

枚举消息钩子 简单粘贴点百度的解释&#xff0c;科普下消息钩子&#xff1a; 钩子是WINDOWS中消息处理机制的一个要点&#xff0c;通过安装各种钩子&#xff0c;应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之前处理它们。 钩子的种类很…

Anti 消息钩子注入

MSDN上对消息钩子的描述&#xff1a; The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for certain types of events. These events are associated either wit…

注入(4)--消息钩子注入(SetWindowsHookEX)

SetWindowsHookEx函数是微软提供给程序开发人员进行消息拦截的一个API。不过,他的功能不仅可以用作消息拦截,还可以进行DLL注入。 SetWindowsHookEx原型声明如下: WINUSERAPI HHOOK WINAPI SetWindowsHookExW(_In_ int idHook,_In_ HOOKPROC lpfn,_In_opt_ HINSTANCE hmod,…

DLL注入技术之消息钩子注入

消息钩子注入原理是利用Windows 系统中SetWindowsHookEx()这个API&#xff0c;他可以拦截目标进程的消息到指定的DLL中导出的函数&#xff0c;利用这个特性&#xff0c;我们可以将DLL注入到指定进程中。主要流程如下图所示 1&#xff0e;准备阶段 需要编写一个DLL&#xff…

关于采用消息钩子机制的透明加密的简单破解

采用消息钩子机制的透明加密方式在各大企业中很常见&#xff0c;简单实用。文件在磁盘上以密文方式存储&#xff0c;打开时首先被加密软件客户端注入的钩子&#xff08;hook&#xff09;截获&#xff0c;解密成明文后再提交给相应程序&#xff1b;保存时同样被钩子截获&#xf…

VC 消息钩子编程

分享一下我老师大神的人工智能教程&#xff01;零基础&#xff0c;通俗易懂&#xff01;http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章。分享知识&#xff0c;造福人民&#xff0c;实现我们中华民族伟大复兴&#xff01; 一、消息钩子的概念 1、基本概念 Windows应…

Windows消息钩子[键盘监控]

之前看书&#xff0c;看到一眼消息钩子&#xff0c;一直没实践&#xff0c;现在有空弄了下&#xff0c; 主要原理是利用windows自带SetWindowsHookEx API函数 HHOOK SetWindowsHookEx( int idHook, //hook形式 HOOKPROC lpfn //hook过程 HI…

一、C++反作弊对抗实战 (基础篇 —— 4.利用消息钩子注入DLL)

这里将主要用到Windows API函数SetWindowsHookEx,它是微软提供给程序开发人员进行消息拦截的一个API,不过它的功能不仅用作消息拦截,还可以进行DLL注入。 一、关于SetWindowsHookEx 提这个函数在微软官网MSDN文档中原型声明如下: SetWindowsHookExA function (winuser.h…

windows10 记事本进程 键盘消息钩子 dll注入

看了很多文档&#xff0c;垮了很多坎&#xff0c;终于完成了这个demo&#xff1b; 有很多个人理解&#xff0c;可能不完全正确&#xff0c;见谅&#xff1b; 先上实现的图片&#xff1a; 如图&#xff0c;我通过SetWindowsHookEx()函数向记事本进程中当前窗口线程注入了自己写…

消息钩子学习工程

前奏 近来一直在自学Windows Hook相关的知识&#xff0c;已经尝试多种注入方式。尤其对消息钩子方式很感兴趣&#xff0c;因为看到Spy能够截获系统中绝大多数应用的消息流&#xff0c;就很想知道它的工作原理&#xff0c;打算制作属于自己的Spy。 消息钩子简介&#xff1a; 消息…

DLL注入技术之消息钩子注入(HOOK简单的实现)

低头不是认输&#xff0c;是要看清自己的路。仰头不是骄傲&#xff0c;是看见自己的天空。——致自己 Hook&#xff0c;是Windows消息处理机制的一个平台&#xff0c;应用程序可以在上面设置子程序以监视指定窗口的某种消息&#xff0c;而且所监视的窗口可以是其他进程所创建的…

powerdesigner制作数据字典

powerdesigner制作数据字典TOC 配置好数据库连接之后&#xff0c;点击File→New Model 这步是默认的点OK就行。 数据传输完之后点击保存。 选择好保存路径后&#xff0c;关闭软件&#xff08;关闭时注意选择保存&#xff09;&#xff0c;然后再重现打开。 重新打开Po…