C++实现观察者模式(包含源码)

news2025/1/12 3:50:07

文章目录

    • 观察者模式
      • 一、基本概念
      • 二、实现方式
      • 三、角色
      • 四、过程
      • 五、结构图
      • 六、构建思路
      • 七、完整代码

观察者模式

一、基本概念

观察者模式(又被称为模型(Model)-视图(View)模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。

二、实现方式

观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察者。

比如在下面的代码表述中,发布作品的DY博主是被观察者,博主的粉丝是观察者 ,当DY博主(被观察者) 发生某种变化时 (状态改变),就会立即通知博主的粉丝 (观察者 )。

三、角色

1、抽象主题(Subject):

它是一个抽象类,也是所有目标对象的父类。它用一个列表记录当前目标对象有哪些观察者对象,并提供增加(Add)、删除观察者对象(Delete)和通知观察者对象的接口。

2、具体主题(ConcreteSubject):

具体目标类,可以有多个不同的具体目标类,它们同时继承Subject类。一个目标对象就是某个具体目标类的对象,一个具体目标类负责定义它自身的事务逻辑,并在状态改变时通知它的所有观察者对象。

3、抽象观察者(Observer):

观察者类,它也是一个抽象类,是所有观察者对象的父类;它为所有的观察者对象都定义了一个名为show的方法(也叫成员函数)。当目标对象的状态改变时,它就是通过调用它的所有观察者对象的show方法来通知它们的。

4、具体观察者(ConcreteObserver):

具体观察者类,可以有多个不同的具体观察者类,它们同时继承Observer类。一个观察者对象就是某个具体观察者类的对象。每个具体观察者类都要重定义Observer类中定义的show方法,在该方法中实现它自己的任务逻辑,当它被通知的时候(目标对象调用它的show方法)就执行自己特有的任务。

四、过程

实现观察者模式有很多形式,比较直观的一种是使用一种“注册—通知—撤销注册”的形式。

观察者

(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。

被观察对象

被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。

撤销观察

观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

五、结构图

img

六、构建思路

我们在前期已经了解了observer和subject的代表意义及用法,下面我们开始构思如何写代码

先写出subject和observer类定义用法

class Observer
{
public:
    virtual void update(){};
    virtual std::string getName()
    {
        return "";
    }
};

class Subject 
{
public:
    void Add(Observer *obs);
    void Delete(Observer *obs);
    void show();
    ~Subject();
private:
    std::vector<Observer *>observer;
};

Observer中的成员函数都是虚函数,不需要强调其作用,只需要了解虚函数的用法;

Subject类的成员函数及变量:

void Add(Observer *obs)---------------增加观察者

void Delete(Observer *obs)------------删除观察者

void show()-----------------------------------当被观察者状态发生改变时,及时通知观察者

~Subject()-------------------------------------析构函数,创建了许多观察者,最后需要析构删除

std::vector<Observer *>observer-----存放观察者的信息,观察者存放到vector容器中

具体主题(ConcreteSubject)和具体观察者(ConcreteObserver)的类定义

class ConcreteSubject : public Subject
{
public:
    std::string getSubjectStatus();
    void   setSubjectStatus(ConcreteSubject * subject, const std::string &str);
private:
    std::string subjectStatus;
};

class ConcreteObserver : public Observer
{
public:
    ConcreteObserver(ConcreteSubject *subject,std::string name);
    std::string getName();
    void update();
private:
    std::string name;
    ConcreteSubject *subject;
    std::string observerStatus;
};

具体主题(ConcreteSubject)类的成员函数及成员变量

std::string getSubjectStatus() -------------------获得被观察者的状态

void setSubjectStatus(ConcreteSubject * subject, const std::string &str) ------------设置被观察者的状态

std::string subjectStatus---------------------------被观察者状态的变量

具体主题(ConcreteObserver)类的成员函数及成员变量

ConcreteObserver(ConcreteSubject *subject,std::string name)---------构造函数,初始化具体观察者

std::string getName()-----------得到观察者的名字

void update() ----------------------当被观察者状态改变时,提醒观察者

std::string observerStatus-----观察者状态

七、完整代码

observer.h

#include<iostream>
#include<vector>

class Observer
{
public:
    virtual void update(){};
    virtual std::string getName()
    {
        return "";
    }
};
class Subject 
{
public:
    void Add(Observer *obs);
    void Delete(Observer *obs);
    void show();
    ~Subject();
private:
    std::vector<Observer *>observer;
};
class ConcreteSubject : public Subject
{
public:
    std::string getSubjectStatus();
    void   setSubjectStatus(ConcreteSubject * subject, const std::string &str);
private:
    std::string subjectStatus;
};
class ConcreteObserver : public Observer
{
public:
    ConcreteObserver(ConcreteSubject *subject,std::string name);
    std::string getName();
    void update();
private:
    std::string name;
    ConcreteSubject *subject;
    std::string observerStatus;
};

observer.cpp

#include "observer.h"
#include<iostream>

void Subject::Add(Observer *obs)
{
    observer.push_back(obs);
}
void Subject::Delete(Observer *obs)
{
    for(auto i = 0;i < observer.size();i++)
    {
        if(obs == observer[i])
        {
            observer.erase(observer.begin() + i);
        }
    }
}
void Subject::show()
{
    auto it = observer.begin();  //vector<Observer*>::iterator
    while(it != observer.end())  
    {
        (*it)->update();        // it是指向observer元素的地址类似于observer.begin()。*it才相当于 observer[i]
        it++;
    }
}
Subject::~Subject()
{
    std::cout<<"执行析构函数------"<<std::endl;
    auto it = observer.begin();
    while(it != observer.end())
    {
        std::cout<<"已经删除:"<<(*it)->getName()<<std::endl;
        delete *it;
        it++;
    }
    observer.clear();
}
std::string ConcreteSubject::getSubjectStatus()
{
    return subjectStatus;
}
void ConcreteSubject::setSubjectStatus(ConcreteSubject * subject,const std::string &str)
{
    subjectStatus = str;
    subject->show();
}
ConcreteObserver::ConcreteObserver(ConcreteSubject *subject,std::string name)
{
    this->subject = subject;
    this->name = name;
}
std::string ConcreteObserver::getName()
{
    return name;
}
void ConcreteObserver::update()
{
    observerStatus = subject->getSubjectStatus();
    std::cout<<"您关注的DY博主更新动态了    粉丝: "<<name<<"用户状态: "<<observerStatus<<std::endl;
}

main.cpp

#include "observer.h"
#include <iostream>
int main()
{
    ConcreteSubject *subject = new ConcreteSubject;
    subject->Add(new ConcreteObserver(subject,"TMG"));
    subject->Add(new ConcreteObserver(subject,"WYA"));
    subject->setSubjectStatus(subject,"在线");
    std::cout<<std::endl;
    delete subject;
}

更多资料点击 GitHub 欢迎各位读者去Star

⭐学术交流群Q 754410389 持续更新中~~~

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

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

相关文章

5G通信与蜂窝模组之间的关系

5G通信是第五代移动通信技术的简称&#xff0c;它代表了一种新一代的无线通信技术标准。5G通信的主要目标是提供更高的数据传输速度、更低的延迟、更大的网络容量以及更可靠的连接&#xff0c;以支持各种新兴应用和服务&#xff0c;包括高清视频流、虚拟现实、物联网&#xff0…

【软考中级】网络工程师:7.下一代互联网

IPv4问题与改进 IPv4存在以下著名的问题&#xff1a; 网络地址短缺&#xff08;32位&#xff09;以二进制数串表示&#xff0c;v4仅有43亿个地址&#xff0c;而IPv6有128位&#xff0c;且以十六进制数串表示。&#xff08;现在还能用v4得益于NAT地址转换&#xff09;地址分配…

pwn学习(3)BUUCTF-rip

下载文件&#xff0c;查看文件信息 IDA64打开&#xff0c;发现危险函数gets(),可以判断存在栈溢出漏洞 接着查看fun()函数&#xff0c;发现是system函数&#xff0c;system是C语言下的一个可以执行shell命令的函数 接下来思路就清晰了&#xff0c;需要用gets函数获取一个长字符…

电力安全智慧云平台:引领更安全的用电新时

电力能源是人类社会不可或缺的重要资源&#xff0c;其安全稳定供应关系到各行各业的正常运转和千家万户的生活质量。然而&#xff0c;随着电力使用的普及&#xff0c;电力安全问题也日益凸显&#xff0c;一旦发生电力事故&#xff0c;不仅会造成巨大的经济损失&#xff0c;还会…

python随手小练

题目&#xff1a; 使用python做一个简单的英雄联盟商城登录界面 具体操作&#xff1a; print("英雄联盟商城登录界面") print("~ * "*15 "~") #找其规律 a "1、用户登录" b "2、新用户注册" c "3、退出系统&quo…

rv1126-rv1109-test

测试指令 播放音频:aplay aigei.wav 测试时间: 查看系统时间:date 设置时间:date -s "2023-09-21 16:00:00" 设置芯片时间:hwclock -w 查看芯片时间:hwclock 测试背光: echo 0 > sys/class/backlight/backlight/brightness echo 50 > sys/class/backlig…

[python 刷题] 167 Two Sum II - Input Array Is Sorted 15 3Sum

[python 刷题] 167 Two Sum II - Input Array Is Sorted & 15 3Sum 虽然 3 sum 出来的比较早&#xff0c;不过按照解法来说&#xff0c;2 sum II 算是 3 sum 的前置解法 167 Two Sum II - Input Array Is Sorted 题目&#xff1a; Given a 1-indexed array of integers …

图像处理软件Photoshop 2024 mac新增功能

Photoshop 2024 mac是一款图像处理软件的最新版本。ps2024提供了丰富的功能和工具&#xff0c;使用户能够对照片、插图、图形等进行精确的编辑和设计。 Photoshop 2024 mac软件特点 快速性能&#xff1a;Photoshop 2024 提供了更快的渲染速度和更高效的处理能力&#xff0c;让用…

中秋国庆抢票用便签软件记录抢票细则

今年的中秋国庆又连为一体&#xff0c;大家都在庆幸着有一个八天的小长假&#xff0c;一年难得有一次这样的机会&#xff0c;趁着这个小长假必然是要好好出去玩一玩的&#xff1b;如果涉及到长途旅游&#xff0c;少不得提前在12306上进行抢票&#xff0c;怎么才能快速抢到票呢&…

网络编程day04(网络属性函数、广播、组播、TCP并发)

今日任务 对于newfd的话&#xff0c;最好是另存然后传入给分支线程&#xff0c;避免父子线程操作同一个文件描述符 1.广播&#xff1a; 接收端 代码&#xff1a; #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h&…

深度学习文本预处理利器:Tokenizer详解

目录 1 Tokenizer 介绍 1.1 Tokenizer定义 1.2 Tokenizer方法 1.3 Tokenizer属性 2 Tokenizer文本向量化 2.1 英文文本向量化 2.2 中文文本向量化 3 总结 1 Tokenizer 介绍 Tokenizer是一个用于向量化文本&#xff0c;将文本转换为序列的类。计算机在处理语言文字时&…

对本地的静态html文件发送http请求

需要对本地的html文件&#xff0c;或者说静态网页发送请求&#xff0c;只有前端页面&#xff0c;没有后端。前端的文件基本都有。 文件链接&#xff1a;D:/mystudysoft/weixinkaifa/WeChat%20Files/wxid_inmlsqlnnpqs22/FileStorage/File/2023-09/%E5%BE%B7%E5%9B%BD%E4%BA%…

聚观早报|高德发布安全出行大模型;小鹏G9焕新上市

【聚观365】9月21日消息 高德发布安全出行大模型 小鹏G9焕新上市 妙鸭相机上线免费版 Redmi Note 13 Pro支持IP68 Neuralink将进行首次人体临床试验 高德发布安全出行大模型 高德发布了安全出行大模型。据介绍&#xff0c;安全出行大模型基于高德的地图大数据、位置大数据…

FPGA project : DS18B20

本想着一天发一个实验的&#xff0c;这个ds18b20&#xff0c;耗时两天。代码写了两次&#xff0c;呜呜~ 由于第二次写代码没画时序图&#xff0c;所以代码和时序图一些参数有些不一致&#xff0c;但问题不大。 这里有几件事情值得一提&#xff1a; 1&#xff1a;关于状态机的…

Linux系统编程——网络编程的学习

Linux系统编程学习相关博文 Linux系统编程——文件编程的学习Linux系统编程——进程的学习Linux系统编程——进程间通信的学习Linux系统编程——线程的学习 Linux系统编程——网络编程的学习 一、概述1. TCP/UDP2. 端口号3. 字节序4. Sockt服务器和客户端的开发步骤1. 服务器2…

网络编程 day4

1->广播模型 接收方 发送方 2->组播模型 接收方 发送方 3->多进程并发服务器 4->多线程并发服务器

openssl 交叉编译(uclibc)

参考文章 openssl 交叉编译_GeYi1998的博客-CSDN博客 本地实际操作一遍,和网上的文章有些不同. 先下载源码 /source/index.html 使用 1.1.1w的版本,最新的3.0.11试了,编译不过,很多gcc的写法问题(error: initializer element is not constant) 解压到 Document 目录下, h…

视频汇聚/视频云存储/视频监控管理平台EasyCVR分发rtsp流起播慢优化步骤详解

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

iOS自动化测试方案(一):MacOS虚拟机保姆级安装Xcode教程

文章目录 一、环境准备二、基础软件三、扩展&#xff1a;usb拓展插件 一、环境准备 1、下载VMware虚拟机的壳子&#xff0c;安装并注册软件(可以百度注册码)&#xff0c;最新版本&#xff1a;v17 2、下MacOS系统iOS镜像文件&#xff0c;用于vmware虚拟机安装&#xff0c;当前镜…

如何用一行CSS实现10种现代布局

现代 CSS 布局使开发人员只需按几下键就可以编写十分有意义且强大的样式规则。上面的讨论和接下来的帖文研究了 10 种强大的 CSS 布局&#xff0c;它们实现了一些非凡的工作。 超级居中&#xff1a;place-items: center 对于第一个“单行”布局&#xff0c;让我们解决所有 CSS…