您现在的位置是:首页 > 文章详情

用c++实现《图解设计模式》——observer模式(老师说这个很常用)

日期:2018-11-28点击:362

他是MVC的重要组成部分

 

动机

 

模式定义

 

结构

 

 

 

 

对于一个实现文件切割的类,如果需要对其增加一个显示进度条的选项,使得用户可以知道文件切割的进度。如果直接在类中增加一个字段来表示进度条,这种修改方式好不好?

代码如下(代码都是伪代码

mainform.cpp

//一个实现文件分割器是类 class MainForm : public Form { //文件路径 TextBox* txtFilePath; //用户希望分隔的文件个数 TextBox* txtFileNumber; //进度条 ProgressBar* progressBar; public: //点击按钮,我们会收集文件信息,然后去调用filespliter void Button1_Click(){ string filePath = txtFilePath->getText(); int number = atoi(txtFileNumber->getText().c_str()); FileSplitter splitter(filePath, number, progressBar); splitter.split(); } }; 

 

对应的实现代码如下:

FileSplitter.cpp

class FileSplitter { string m_filePath; int m_fileNumber; ProgressBar* m_progressBar; public: FileSplitter(const string& filePath, int fileNumber, ProgressBar* progressBar) : m_filePath(filePath), m_fileNumber(fileNumber), m_progressBar(progressBar){ } void split(){ //1.读取大文件 //2.分批次向小文件中写入 for (int i = 0; i < m_fileNumber; i++){ //... float progressValue = m_fileNumber; progressValue = (i + 1) / progressValue; //更新进度条的进展 m_progressBar->setValue(progressValue); } } };

 

 

直接在类里面添加字段,这样是不合适的,违背了八大设计原则。如果以后的需求还有变更,还继续对类进行修改吗?这样是不对的。

依赖倒置原则给我们的一个说法——不要去依赖A,而是我依赖A的抽象基类。

但是单纯的按照找父类的方式去寻找,你会发现走进了死胡同。因为fliesplitter.cpp文件实现进度条绘制的函数setValue()在ProgressBar的父类中并不存在。因此,单纯找基类是一个很粗浅的认识,

 

仔细分析你会发现,ProgressBar在类中扮演的角色是依赖通知。

对于通知,其实我们可以用相对抽象的方式来表达通知,而不是具体控件来表达通知。(下面代码中添加了一个IProgress这样一抽象接口类,来解开耦合性)

 

tip:c++的多继承容易引发一些耦合性的问题,但是如果子类都只是实现一个个的接口,这样的多继承还是很推荐的

 

根据依赖倒置原则修改后的代码

mainform.cpp

class MainForm : public Form, public IProgress { TextBox* txtFilePath; TextBox* txtFileNumber; ProgressBar* progressBar; public: void Button1_Click(){ string filePath = txtFilePath->getText(); int number = atoi(txtFileNumber->getText().c_str()); ConsoleNotifier cn; FileSplitter splitter(filePath, number); splitter.addIProgress(this); //订阅通知 splitter.addIProgress(&cn); //订阅通知 splitter.split(); splitter.removeIProgress(this); } virtual void DoProgress(float value){ //这里可以实现progressBar,因为mainForm和progressBar本身就是一体的 progressBar->setValue(value); } }; class ConsoleNotifier : public IProgress { public: virtual void DoProgress(float value){ cout << "."; } }; 

 

FileSplitter.cpp

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

 

 

总结

 

 

————————————————————————————————————————————————————————

来自《图解设计模式》的补充

 

观察者模式,当观察对象发生变化时,会通知给观察者。

观察者模式适用于根据对象状态而做出相应处理的场景。

 

 

原文链接:https://yq.aliyun.com/articles/681120
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章