[大话设计模式C++版] 第14章 老板回来,我不知道 —— 观察者模式

2023-11-14

源码可以在这里找到 大话设计模式C++版

双向耦合的代码

//Secretary.h 秘书类
#include <QList>

using namespace std;
class StockObserver;

class Secretary
{
private:
    QList<shared_ptr<StockObserver>> observers;
    QString action;

public:
    void Attach(shared_ptr<StockObserver> observer) {
        this->observers.append(observer);
    }
    void Notify() {
        for (int i = 0; i < this->observers.size(); i++) {
            this->observers[i]->Update();
        }
    }
    const QString &getAction() const {
        return action;
    }
    void setAction(const QString &newAction) {
        action = newAction;
    }
};
//StockObserver.h
#pragma execution_character_set("utf-8")
#include "Secretary.h"
#include <QDebug>

using namespace std;

class StockObserver
{
private:
    QString name;
    shared_ptr<Secretary> sub;

public:
    StockObserver(QString name, shared_ptr<Secretary> sub) {
        this->name = name;
        this->sub = sub;
    }
    void Update() {
        qDebug() << QString("%1 %2 关闭股票行情,继续工作!").arg(sub->getAction()).arg(name);
    }
};
//main.cpp
#pragma execution_character_set("utf-8")
#include "Secretary.h"
#include "StockObserver.h"

using namespace std;

int main(int argc, char *argv[])
{
    //前台小姐童子喆
    shared_ptr<Secretary> tongzizhe(new Secretary());
    //看股票的同时
    shared_ptr<StockObserver> tongshi1(new StockObserver("魏关姹", tongzizhe));
    shared_ptr<StockObserver> tongshi2(new StockObserver("易管查", tongzizhe));

    //前台记下了两位同时
    tongzizhe->Attach(tongshi1);
    tongzizhe->Attach(tongshi2);
    //发现老板回来
    tongzizhe->setAction("老板回来了!");
    //通知两个同事
    tongzizhe->Notify();

    return 0;
}

运行结果:

老板回来了! 魏关姹 关闭股票行情,继续工作!
老板回来了! 易管查 关闭股票行情,继续工作!

Secretary类StockObserver类 相互耦合,Secretary类 要增加观察者,StockObserver类 要前台的状态,如果需要增加NBA直播观察者,Secretary类 需要修改,违反了 开放-封闭原则。导致违 开放-封闭原则 的原因是没有遵守 依赖-倒转原则 ,我们应该让程序都依赖抽象,而不是相互依赖。

解耦实践一

//Observer.h 增加抽象观察者类
#include <QString>
#include <memory>

using namespace std;

class Secretary;

class Observer
{
protected:
    QString name;
    shared_ptr<Secretary> sub;
public:
    Observer(QString name, shared_ptr<Secretary> sub) {
        this->name = name;
        this->sub = sub;
    }
    virtual void Update() = 0;
};
//StockObserver.h 具体观察者
#pragma execution_character_set("utf-8")
#include "Observer.h"
#include "Secretary.h"
#include <QDebug>

using namespace std;

class StockObserver : public Observer
{
public:
    StockObserver(QString name, shared_ptr<Secretary> sub) : Observer(name, sub) {}
    void Update() {
        qDebug() << QString("%1 %2 关闭股票行情,继续工作!").arg(sub->getAction()).arg(name);
    }
};
//NBAObserver.h 具体观察者
#pragma execution_character_set("utf-8")
#include "Observer.h"
#include "Secretary.h"
#include <QDebug>

using namespace std;

class NBAObserver : public Observer
{
public:
    NBAObserver(QString name, shared_ptr<Secretary> sub) : Observer(name, sub) {}
    void Update() {
        qDebug() << QString("%1 %2 关闭NBA直播,继续工作!").arg(sub->getAction()).arg(name);
    }
};
//Secretary.h 前台类中的具体观察者类换成抽象观察者类
#include <QList>
#include "Observer.h"

using namespace std;

class Secretary
{
private:
    QList<shared_ptr<Observer>> observers;
    QString action;

public:
    void Attach(shared_ptr<Observer> observer) {
        this->observers.append(observer);
    }
    void Detach(shared_ptr<Observer> observer) {
        this->observers.removeOne(observer);
    }
    void Notify() {
        for (int i = 0; i < this->observers.size(); i++) {
            this->observers[i]->Update();
        }
    }
    const QString &getAction() const {
        return action;
    }
    void setAction(const QString &newAction) {
        action = newAction;
    }
};

StockObserver类NBAObserver类 具体观察者类与 Secretary类 具体被观察者类耦合,违反了 依赖-倒转原则 原则,被观察者类也需要做成抽象类

解耦实践二

//Subject.h 抽象被观察者(抽象通知者)
#include "Observer.h"

using namespace std;

class Subject
{
protected:
    QString action;
public:
    virtual void Attach(shared_ptr<Observer> observer) = 0;
    virtual void Detach(shared_ptr<Observer> observer) = 0;
    virtual void Notify() = 0;
    const QString &getAction() const {
        return action;
    }
    void setAction(const QString &newAction) {
        action = newAction;
    }
};
//Boss.h 具体通知者
#include <QList>
#include "Subject.h"
#include "Observer.h"

class Boss : public Subject
{
private:
    QList<shared_ptr<Observer>> observers;
    QString action;
public:
    virtual void Attach(shared_ptr<Observer> observer) {
        this->observers.append(observer);
    }
    virtual void Detach(shared_ptr<Observer> observer) {
        this->observers.removeOne(observer);
    }
    virtual void Notify() {
        for (int i = 0; i < this->observers.size(); i++) {
            this->observers[i]->Update();
        }
    }
};
//Observer.h 抽象观察者
#include <QString>
#include <memory>

using namespace std;

class Subject;

class Observer
{
protected:
    QString name;
    shared_ptr<Subject> sub;
public:
    Observer(QString name, shared_ptr<Subject> sub) {
    	this->name = name;
        this->sub = sub;
    }
    virtual void Update() = 0;
};
//StockObserver.h 看股票的同事
#pragma execution_character_set("utf-8")
#include "Observer.h"
#include "Subject.h"

using namespace std;

class StockObserver : public Observer
{
public:
    StockObserver(QString name, shared_ptr<Subject> sub) : Observer(name, sub) {}
    virtual void Update() override {
        qDebug() << QString("%1 %2 关闭股票行情,继续工作!").arg(sub->getAction()).arg(name);
    }
};
//main.cpp 客户端代码
#pragma execution_character_set("utf-8")
#include "Secretary.h"
#include "StockObserver.h"
#include "NBAObserver.h"
#include "Boss.h"

using namespace std;

int main(int argc, char *argv[])
{
    //老板胡汉三
    auto huhansan = shared_ptr<Boss>(new Boss());

    //看股票的同事
    auto tongshi1 = shared_ptr<StockObserver>(new StockObserver("魏关姹", huhansan));
    //看NBA的同事
    auto tongshi2 = shared_ptr<NBAObserver>(new NBAObserver("易管查", huhansan));

    huhansan->Attach(tongshi1);
    huhansan->Attach(tongshi2);

    huhansan->Detach(tongshi1);

    //老板回来
    huhansan->setAction("我胡汉三回来了!");
    //发出通知
    huhansan->Notify();

    return 0;
}

运行结果:

我胡汉三回来了! 易管查 关闭NBA直播,继续工作!

代码结构图:

在这里插入图片描述

Observer观察者模式 [李建忠C++笔记]

“组件协作”模式

  • 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
  • 典型模式
    • Template Method
    • Strategy
    • Observer / Event

动机(Motivation)

  • 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
  • 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
//MainForm.h
class MainForm : public Form, public IProgress
{
private:
    TextBox* txtFilePath;
    TextBox* txtFileNumber;

    ProgressBar* progressBar;
	ConsoleNotifier cn;
public:
    void Button1_Click() {
        string filePath = txtFilePath->getText();
        int number = atoi(txtFileNumber->getText().c_str());
		
        FileSplitter splitter(filePath, number);
		splitter.addIProgress(this);
		splitter.addIProgress(&cn);
		
        splitter.split();
		splitter.removeIProgress(&cn);
    }
	
	void DoProgress(float value) {
		progressBar->setValue(value);
	}
};

class ConsoleNotifier : public IProgress
{
public:
	void DoProgress(float value) {
		cout << ".";
	}
};
//FileSplitter.h
class IProgress 
{
public:
	virtual void DoProgress(float value) = 0;
	virtual ~IProgress() {}
};

class FileSplitter
{
    string m_filePath;
    int m_fileNumber;
	
	//ProgressBar* m_progressBar;  //通知控件
	List<IProgress*> m_iprogressList;  //抽象通知机制,支持多个观察者
public:
    FileSplitter(const string& filePath, int fileNumber) 
		: m_filePath(filePath), m_fileNumber(fileNumber) {}
		
	void addIProgress(IProgress* iprogress) {
		m_iprogressVector.add(iprogress);
	}
	
	void removeIProgress(IProgress* iprogress) {
		m_iprogressVector.remove(iprogress);
	}
		
    void split() {
        //1.读取大文件
        
        //2.分批次向小文件中写入
        for (int i = 0; i < m_fileNumber; i++) {
            //...
			float progressValue = m_fileNumber;
			progressValue = (i+1) / progressValue;
			onProgress(progressValue);
        }
    }
	
protected:
	void onProgress(float value) {
		List<IProgress*>::Iterator itor = m_iprogressList.begin();
		
		//...
		while (itor != m_iprogressList.end()) {
			(*itor)->DoProgress(value);  //更新进度条
			itor++;
		}
	}
};

模式定义

定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖与它的对象都得到通知并自动更新。——《设计模式》GoF

在这里插入图片描述

要点总结

  • 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
  • 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
  • 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
  • Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[大话设计模式C++版] 第14章 老板回来,我不知道 —— 观察者模式 的相关文章

  • 向进度条添加百分比文本 C#

    我有一个方法可以显示进程栏何时正在执行以及何时成功完成 我工作得很好 但我想添加一个百分比 如果完成 则显示 100 如果卡在某个地方 则显示更少 我在网上做了一些研究 但我无法适应我正在寻找的解决方案 这是我的代码 private voi
  • 使用 std::packaged_task/std::exception_ptr 时,线程清理程序报告数据争用

    我遇到了线程清理程序 TSan 的一些问题 抱怨某些生产代码中的数据争用 其中 std packaged task 通过将它们包装在 std function 中而移交给调度程序线程 对于这个问题 我简化了它在生产中的作用 同时触发 TSa
  • 如何将 protobuf-net 与不可变值类型一起使用?

    假设我有一个像这样的不可变值类型 Serializable DataContract public struct MyValueType ISerializable private readonly int x private readon
  • 如何让 Swagger 插件在自托管服务堆栈中工作

    我已经用 github 上提供的示例重新提出了这个问题 并为任何想要自己运行代码的人提供了一个下拉框下载链接 Swagger 无法在自托管 ServiceStack 服务上工作 https stackoverflow com questio
  • 提交后禁用按钮

    当用户提交付款表单并且发布表单的代码导致 Firefox 中出现重复发布时 我试图禁用按钮 去掉代码就不会出现这个问题 在firefox以外的任何浏览器中也不会出现这个问题 知道如何防止双重帖子吗 System Text StringBui
  • 为什么 Google 测试会出现段错误?

    我是 Google Test 的新手 正在尝试提供的示例 我的问题是 当我引入失败并设置GTEST BREAK ON FAILURE 1 或使用命令行选项 GTest 将出现段错误 我正在考虑这个例子 https code google c
  • 使用接口有什么好处?

    使用接口有什么用 我听说它用来代替多重继承 并且还可以用它来完成数据隐藏 还有其他优点吗 哪些地方使用了接口 程序员如何识别需要该接口 有什么区别explicit interface implementation and implicit
  • 在 C 中初始化变量

    我知道有时如果你不初始化int 如果打印整数 您将得到一个随机数 但将所有内容初始化为零似乎有点愚蠢 我问这个问题是因为我正在评论我的 C 项目 而且我对缩进非常直接 并且它可以完全编译 90 90 谢谢 Stackoverflow 但我想
  • 在一个平台上,对于所有数据类型,所有数据指针的大小是否相同? [复制]

    这个问题在这里已经有答案了 Are char int long 甚至long long 大小相同 在给定平台上 不能保证它们的大小相同 尽管在我有使用经验的平台上它们通常是相同的 C 2011 在线草稿 http www open std
  • 具有交替类型的可变参数模板参数包

    我想知道是否可以使用参数包捕获交替参数模式 例如 template
  • 如何在 Xaml 文本中添加电子邮件链接?

    我在 Windows Phone 8 应用程序中有一些大文本 我希望其中有电子邮件链接 例如 mailto 功能 这是代码的一部分
  • C#:帮助理解 UML 类图中的 <>

    我目前正在做一个项目 我们必须从 UML 图编写代码 我了解 UML 类图的剖析 但我无法理解什么 lt
  • 为什么 std::strstream 被弃用?

    我最近发现std strstream已被弃用 取而代之的是std stringstream 我已经有一段时间没有使用它了 但它做了我当时需要做的事情 所以很惊讶听到它的弃用 我的问题是为什么做出这个决定 有什么好处std stringstr
  • CMake 无法确定目标的链接器语言

    首先 我查看了this https stackoverflow com questions 11801186 cmake unable to determine linker language with c发帖并找不到解决我的问题的方法 我
  • 动态添加 ASP.Net 控件

    我有一个存储过程 它根据数据库中存储的记录数返回多行 现在我想有一种方法来创建 div 带有包含该行值的控件的标记 如果从数据库返回 10 行 则 10 div 必须创建标签 我有下面的代码来从数据库中获取结果 但我不知道如何从这里继续 S
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • 方法优化 - C#

    我开发了一种方法 允许我通过参数传入表 字符串 列数组 字符串 和值数组 对象 然后使用这些参数创建参数化查询 虽然它工作得很好 但代码的长度以及多个 for 循环散发出一种代码味道 特别是我觉得我用来在列和值之间插入逗号的方法可以用不同的
  • 如何部署“SQL Server Express + EF”应用程序

    这是我第一次部署使用 SQL Server Express 数据库的应用程序 我首先使用实体 框架模型来联系数据库 我使用 Install Shield 创建了一个安装向导来安装应用程序 这些是我在目标计算机中安装应用程序所执行的步骤 安装
  • 从列表中选择项目以求和

    我有一个包含数值的项目列表 我需要使用这些项目求和 我需要你的帮助来构建这样的算法 下面是一个用 C 编写的示例 描述了我的问题 int sum 21 List
  • 当我使用 OpenSSL1.1.0g 根据固定的 p 和 g 值创建 Diffie Hellman 密钥协议密钥时,应该执行哪些检查?

    您好 我尝试通过这段代码使用修复 p 和 g 参数来制作 Diffie Hellman Keysanswer https stackoverflow com a 54538811 4706711 include

随机推荐

  • 【经验分享】- 这是一份来自 IT 男的电脑使用建议

    这是一份来自 IT 男的电脑使用建议 1 写在前面 2018 年高考结束我拿到了第一台笔记本电脑 此前对电脑接触地并不多 因此在这几年的电脑使用过程中积累了一些个人使用经验和使用技巧想要分享给可能还是电脑小白的你 个人一直以来用的还是 Wi
  • 自己动手定制Chromium系列之四:Chromium 58的一个编译配置

    aec untrusted delay for testing Current value from the default false From third party webrtc modules audio processing BU
  • (成功解决)Python连接clickhouse

    第一次尝试用Python连接clickhouse数据库 踩了不少坑 特此记录 帮助后人少犯错 运行环境 python 3 8 3 clickhouse driver 0 2 3 clickhouse sqlalchemy 0 2 0 sql
  • Linux-(C/C++)动态链接库生成以及使用(libxxx.so)

    linux静态库生成与使用 http www cnblogs com johnice archive 2013 01 17 2864319 html Linux中so文件为共享库 与windows下dll类似 不过实现要简单 so可以供多个
  • 小熊错误_小熊派4G开发板初体验

    开发板硬件资源介绍 前阵子小熊派发布了一款超高性价比的4G开发板 但是板子仅限量1000套 小熊派官方给我送了一块 我们一起来学习学习 板子做得小巧精致 控制核心用的是移远的EC100Y LTE Cat1无线通信模组 该模组可对所有用户开放
  • Python开发环境Wing IDE如何使用调试功能

    在使用Wing IDE开始调试的时候 需要设置断点的行 读取GetItemCount函数的返回 这可以通过单击行并选择Break工具栏条目 或通过单击行左边的黑色边缘 断点应该以实心红圈的形式出现 接下来使用绿色箭头图标开始调试或在Debu
  • 基于微信小程序的健身小助手小程序

    文末联系获取源码 开发语言 Java 框架 ssm JDK版本 JDK1 8 服务器 tomcat7 数据库 mysql 5 7 8 0 数据库工具 Navicat11 开发软件 eclipse myeclipse idea Maven包
  • Mysql中分组后取最新的一条数据

    在 SQL 中 你可以使用子查询和 ORDER BY 子句来实现按照特定字段进行分组 并获取每个分组中最新的一条记录 SELECT t1 FROM your table t1 INNER JOIN SELECT id MAX timesta
  • 云技术平台赋能媒体融合发展创新

    欢迎大家前往腾讯云技术社区 获取更多腾讯海量技术实践干货哦 作者 熊普江 媒体行业是传统而又新兴的行业 在数字化 信息化 移动化快速演进的今天 无论是用户 社会还是行业 政府都意识到 传统媒体与新兴媒体融合发展是必然之路 但媒体融合需要内容
  • 2021-07-14 React 代码规范整理

    文章目录 React 代码规范 1 基础规则 2 组件声明 1 组件名称和定义该组件的文件名称建议要保持一致 2 不要使用 displayName 属性来定义组件的名称 应该在 class 或者 function 关键字后面直接声明组件的名
  • 烟花代码

    div div
  • 日志-Log4J

    日志 程序中的日志可以用来记录程序在运行的时候点点滴滴 并可以进行永久存储 日志和输出语句的区别 输出语句 日志技术 取消日志 需要修改代码 灵活性比较差 不需要修改代码 灵活性比较好 输出位置 只能是控制台 可以将日志信息写入到文件或者数
  • R语言之 as.formula()

    今天学到一个东西 R 语言回归函数里面的公式函数 as formula 其作用就是将字符串转换成公式 gt aa ReadCount Age BMI Sex HAMD 1 1 Sex gt aa 1 ReadCount Age BMI Se
  • MFC之滑块与旋转控件23

    1 滑块 首先看看滑块相关的内容 从sitch看到 滑块分为五个内容 分别是矩形滑块位置 滑块左右两边的箭头 和矩形滑块分别距离左右两边的空间 1 先添加滑块控件和显示矩形滑块的位置编辑区 2 右击编辑区添加变量为int类型 3 添加滑块为
  • Qt实现不同项目的信号传递

    Qt实现windows通信 不同项目的窗口通信 有关Qt通信的知识 windows要实现不同项目窗口通信 需要用类似于windows h的api接口 数据传输主要通过 typedef struct tagCOPYDATASTRUCT cds
  • nowcoder-15165-字符串问题-kmp

    题目描述 有一个字符串 让你找到这个字符串 S 里面的子串T 这个子串 T 必须满足即使这个串的前缀 也是这个 串的后缀 并且 在字符串中也出现过一次的 提示 要求满足前后缀的同时也要在字符串中出现一次 只是前后缀可不行 输出最长满足要求字
  • Shell脚本进阶版合集

    文章目录 一 Linux监控服务端口脚本 二 Linux编译安装Nginx脚本 三 Linux监控一个主机状态脚本 四 Linux统计内存 CPU使用前十进程脚本 五 Linux 磁盘I O列长度监控脚本 六 Linux计算内存使用率占比
  • 【多元统计分析】09.独立性检验与正态性检验

    文章目录 九 独立性检验和正态性检验 1 独立性检验 2 一元数据正态性检验 3 多元数据的正态性检验 回顾总结 九 独立性检验和正态性检验 1 独立性检验 独立性检验 指的是将一个多元总体 X N p
  • 【cmake】find_package设置查找路径

    1 find package的作用与实例 用来查找第三方依赖包的 cmake文件 并根据 cmake文件生成依赖包的头文件目录和库文件路径等 CMakeLists txt实例 find package Protobuf REQUIRED i
  • [大话设计模式C++版] 第14章 老板回来,我不知道 —— 观察者模式

    源码可以在这里找到 大话设计模式C 版 双向耦合的代码 Secretary h 秘书类 include