【组件协作】 观察者模式

文章目录

  • 观察者模式
    • 代码
    • 优化
    • 总结

观察者模式

观察者模式仍然是一个组件协作式的设计模式, 目的在于解决框架的协作问题, 我们需要为某些对象建立
一种“通知依赖关系”, 也就是说, 当一个对象(目标对象)的状态发生改变的时候, 所有的依赖对象(观察者对象)
都将得到通知。 如果这也的依赖关系过于紧密, 则过度耦合

代码

假设现在我们需要一个文件分割器, 我们需要一个界面和一个提供实际功能的类
原始状态
MainForm.cpp

class MainForm : public Form
{TextBox* txtFilePath_;TextBot* txtFileNumber_;
public:void BtnClick(){string filePath = txtFilePath_->getText();int number = atoi(txtFileNumber_->getText().c_str());FileSplitter splitter(filePath, number);splitter.Split();}
};

FileSplitter.cpp

class FileSplitter
{string filePath_;int fileNumber_;
public:FileSplitter(const string& filePath, int fileNumber) : filePath_(filePath), fileNumber_(fileNumber) {}void split(){// I// Ofor (size_t i = 0; i < fileNumber_; i ++ ){// code...}}
};

现在有个需求:假设文件巨无敌大, 那么分割会很慢, 现在需要一个进度条进行展示, 不然用户看不到进度会很焦虑
也就是说, MainForm要添加一个类似于ProgressBar的类作为成员变量, 用来展示分割进度

MainForm.cpp

class MainForm : public Form
{TextBox* txtFilePath_;TextBot* txtFileNumber_;ProgressBar* progressBar_;
public:void BtnClick(){string filePath = txtFilePath_->getText();int number = atoi(txtFileNumber_->getText().c_str());FileSplitter splitter(filePath, number, progressBar_);splitter.Split();}
};

FileSplitter.cpp


class FileSplitter
{string filePath_;int fileNumber_;ProgressBar* progressBar_;
public:FileSplitter(const string& filePath, int fileNumber, ProgressBar* progressBar) : filePath_(filePath), fileNumber_(fileNumber), progressBar_(progressBar) {}void split(){// I// Ofor (size_t i = 0; i < fileNumber_; i ++ ){// code...if (progressBar_){progressBar_->setValue(i * 100 / fileNumber_);}}}
};

优化

上面写法很明显违背了依赖倒置原则, 高层模块不应该依赖底层, 二者都应该依赖抽象, 抽象不应该依赖细节,细节应该依赖抽象

什么是依赖?
A依赖B, 意思是A编译的时候, B需要存在, 这个时候才能编译通过
FileSplitter依赖ProgressBar, 那么FileSplitter编译的时候,ProgressBar需要存在, 才能编译通过
但是, 进度条的实现只有ProgressBar这么一种吗?
显然不是

为什么不应该依赖细节?因为细节非常容易变化
怎么重构呢?
依赖倒置原则给我们提供了方案, 我们应该依赖抽象, 假如ProgressBar有一个父类:ControlBase, 那么FileSplitter就依赖ControlBase
但如果是这样的话,
FileSplitter类里的for循环怎么处理?
父类一定会有这个抽象函数吗?
所以, 单纯的找父类是一个很粗浅的认识, 要明白, 咱们的ProgressBar在系统中的角色
显然:ProgressBar是一个通知, 而不是控件, 通知才是这个组件的根本属性
而控件太detail了

Interface: IProgressBar
IProgressBar.cpp

class IProgress
{
public:virtual void DoProgress(float value) = 0;virtual ~IProgress(){}
};

ProgressBar是一个具体的通知控件, 而IProgressBar是一个抽象的通知机制
此时就可以把FileSplitter的ProgressBar更换成IprogressBar了
然后去调用DoProgress函数


至于MainForm类的话, 使用多继承
继承Form和IProgressBar, 并且实现IProgressBar的DoProgress函数

MainForm.cpp

virtual void MainForm::DoProgress(float value)
{progressBar_->setValue(value);  
}

重构优化到这里, 已经非常松耦合了, 并且遵从依赖倒置原则
但是···如果要支持多个通知呢?也就是说, 要支持多个观察者, 怎么做?

ConsoleNotifiler.cpp

class ConsoleNotifier : public IProgress
{
public:virtual void MainForm::DoProgress(float value){progressBar_->setValue(value);  cout << ".";}
};

第一处更改的地方, 就是将IprogressBar换成std::vector<IProgress*>, 当然, 也可以更换成List
第二处修改时增加了一个增加/删除/遍历成员的接口
ConsoleNotifiler.cpp

void addItem(IProgress* item)
{iprogressVec.push_back(item);
}void removeItem(IProgress* item)
{iprogressVec.remove(item);
}// 遍历
void forEach()
{// code...
}// 返回迭代器
void Begin()
{// code...
}void End()
{// code...
}

然后只需要遍历每个Iprogress, 调用DoProgress函数即可

总结

观察者模式是一种组件间协作的设置模式, 用于一对多的通知机制
目标发送通知的时候, 无需指定观察者,通知(可以携带通知信息作为参数)会自动传播(调用DoProgress函数)

观察者自己确定是否需要订阅通知(订阅通知就是上面的add),目标对象对此一无所知

观察者模式常常用于基于事件的UI框架中, 也是MVC模式的一个重要组成成分

特别的, 调用DoProgress函数并不是通知观察者, 而是执行通知机制, 只是说执行结果为:通知所有的观察者

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

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

相关文章

Git原理与用法系统总结

目录 Reference前言版本控制系统Git的诞生配置Git配置用户名和邮件配置颜色配置.gitignore文件 Git的基础用法初始化仓库克隆现有的仓库添加暂存文件提交变动到仓库比较变动查看日志Git回退Git重置暂存区 Git版本管理重新提交取消暂存撤销对文件的修改 Git分支Git分支的优势Git…

5、注册字符类设备

字符设备 cdev结构体 Linux中使用cdev结构体描述一个字符设备。结构体定义在include/linux/cdev.h 文件中&#xff0c; struct cdev{struct kobject kobj;struct module *owner; //所属模块const struct file_operations *ops; //文件操作结构体struct list_head lis…

《Java初阶数据结构》----5.<二叉树的概念及使用>

前言 大家好&#xff0c;我目前在学习java。之前也学了一段时间&#xff0c;但是没有发布博客。时间过的真的很快。我会利用好这个暑假&#xff0c;来复习之前学过的内容&#xff0c;并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区…

综合点评!史上最强开源大模型Llama 3.1

在人工智能领域&#xff0c;开源模型一直是推动技术进步和创新的重要力量。 北美时间7月23日&#xff0c;Meta公司&#xff08;原Facebook&#xff09;宣布了一项重大突破&#xff1a;开源模型Llama 3.1的正式发布。这一举措预示着AI技术的又一次飞跃&#xff0c;Llama 3.1有望…

虚拟化数据恢复—XenServer VPS不可用如何恢复数据?

虚拟化数据恢复环境&#xff1a; 某品牌R720服务器&#xff0c;4块STAT硬盘通过H710P阵列卡组建了一组raid10磁盘阵列。服务器上部署XenServer虚拟化平台&#xff0c;虚拟机安装Windows Server系统&#xff0c;作为Web服务器使用&#xff0c;运行SQL Server数据库。共有2个虚拟…

【数据结构】——堆的实现与算法

目录 一、堆的实现 1.1堆数据的插入 1.2堆数据的删除 二、建堆算法 2.1向上调整建堆 2.2向下调整建堆 三、堆的应用 3.1堆排序 3.2Top—K问题 一、堆的实现 1.1堆数据的插入 插入一个数据后不再是小堆需要将新数据调整到合适的位置&#xff0c;所以堆的插入就是在数组…

类和对象(中 )C++

默认成员函数就是用户不显示实现&#xff0c;编译器会自动实现的成员函数叫做默认成员函数。一个类&#xff0c;我们在不写的情况下&#xff0c;编译器会自动实现6个默认成员函数&#xff0c;需要注意&#xff0c;最重要的是前4个&#xff0c;其次就是C11以后还会增加两个默认成…

onlyoffice用nginx反向代理

我对于onlyoffice的需求就是当个在线编辑器使用。在集成react的时候之前都是写的绝对路径的地址&#xff0c;这样在需要迁移应用的时候就造成了巨大的麻烦&#xff0c;所以我决定用nginx做反向代理&#xff0c;这样我集成的时候就不用每次都修改源码中的地址了。 一开始写的代…

昇思25天学习打卡营第XX天|基于MindSpore通过GPT实现情感分类

其实数据集和模型的其他大平台接口的&#xff0c;感觉不用非包在自己包里 %env HF_ENDPOINThttps://hf-mirror.com mindnlp.transformers 库中的 GPTTokenizer 类来加载和处理与GPT&#xff08;生成式预训练变换器&#xff09;模型兼容的分词器&#xff0c;并添加特殊的控制标…

Spring源码(八)--Spring实例化的策略

Spring实例化的策略有几种 &#xff0c;可以看一下 InstantiationStrategy 相关的类。 UML 结构图 InstantiationStrategy的实现类有 SimpleInstantiationStrategy。 CglibSubclassingInstantiationStrategy 又继承了SimpleInstantiationStrategy。 InstantiationStrategy I…

SpringBoot通过3种方式实现AOP切面

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…

Sonar-Scanner: 静态代码分析的利器

Sonar-Scanner: 静态代码分析的利器 懂得享受生活的过程&#xff0c;人生才会更有乐趣。每个人都会遇到一些陷阱&#xff0c;每个人都有过去&#xff0c;有的甚至是失败的往事。过去的错误和耻辱只能说明过去&#xff0c;真正能代表人一生的&#xff0c;是他现在和将来的作为。…

【更新2022】省级农民专业合作社数量 无缺失 2006-2022

省级农民专业合作社数量是研究中国农村经济组织和农业社会化服务的重要数据。这些数据可以用来分析不同省份农业生产组织形式的多样性及其对农民生产、技术创新和收入增长的影响。研究者可以基于这些数据&#xff0c;探讨农民专业合作社在提升农产品质量、优化农业生产结构和推…

Transformer处理文本分类实例(Pytorch)

文章目录 Transformer处理文本分类实例参考网站我们构建一个实例问题,预测AG_NEWS的文本分类AG_NEWS数据集介绍预测目标总体思路(简述)主要流程数据预处理dataset构建(不是重点)构建词表 编写处理模型执行词嵌入位置编码(PositionalEncoding)(*核心)多层Transformer模块多头自注…

Mojo数据类型详解

Mojo 中的所有值都分配有相对应的数据类型&#xff0c;大多数类型都是由结构体定义的标称的类型。这些类型是标称的&#xff08;或“命名的”&#xff09;&#xff0c;因为类型相等性是由类型的名称而不是其结构决定的。 有一些类型未定义为结构&#xff0c;例如下面的两种情况…

百款精选的HTML5小游戏源码,你可以下载并直接运行在你的小程序或者自己的网站上

今天我带来了一份特别的礼物——百款精选的HTML5小游戏源码&#xff0c;你可以下载并直接运行在你的小程序或者自己的网站上&#xff0c;只需双击index.html即可开始。无论你是在寻找创意引流&#xff0c;还是想为你的网站增添互动性&#xff0c;这些小游戏都能帮你实现&#x…

办公必备!一键把PDF转换为PPT文件,只需这3款神器!

在当今数字化办公环境中&#xff0c;文件格式的转换已成为提高工作效率的关键因素之一。其中&#xff0c;PDF(便携式文档格式)和PPT(PowerPoint演示文稿)是两种广泛使用的文件格式。然而&#xff0c;有时我们需要将PDF文件转换为PPT格式&#xff0c;以便进行编辑或演示。 为方…

数据结构的基本概念与算法

数据结构的基本概念与算法 什么是数据&#xff1f; 数据是信息的载体&#xff0c;是描述客观事物属性的数、字符以及所有能输入到计算机中并被计算机程序识别和处理的符号的集合&#xff1b;总结来说 -> 数据就是计算机程序加工的原料&#xff1b; 数据元素、数据项&#xf…

<数据集>棉花识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;13765张 标注数量(xml文件个数)&#xff1a;13765 标注数量(txt文件个数)&#xff1a;13765 标注类别数&#xff1a;4 标注类别名称&#xff1a;[Partially opened, Fully opened boll, Defected boll, Flower] 序…

Java面试——Tomcat

优质博文&#xff1a;IT_BLOG_CN 一、Tomcat 顶层架构 Tomcat中最顶层的容器是Server&#xff0c;代表着整个服务器&#xff0c;从上图中可以看出&#xff0c;一个Server可以包含至少一个Service&#xff0c;用于具体提供服务。Service主要包含两个部分&#xff1a;Connector和…