设计模式-观察者模式

class MainForm : public Form{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar; // 增加进度条
public:
void Button1_Click(){
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str() ):
FileSplitter splitter(filePath, number, progressBar);
splitter.split();
}
};

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++){
//...
if (m_progressBar != nullptr){
progressBar->setValue( (i + 1) / m_fileNumber); // 更新进度条
}
}
}
};

违背了依赖倒置设计原则


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

class FileSplitter{
string m_filePath;
int m_fileNumber;
//ProgressBar* m_progressBar; // 具体通知控件
IProgress* m_iprogress; //抽象通知机制
public:
FileSplitter(const string& filePath, int fileNumber, IProgress* iprogress): m_filePath(filePath),
m_fileNumber(fileNumber),
m_iprogress(iprogress){
}
void split(){
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++){
//...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
onProgress(progressValue);
}
}
protected:
virtual void onProgress(float value){
if (m_iprogress != nullptr){
m_iprogress->DoProgress(progressValue); // 更新进度条
}
}
};

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() ):
FileSplitter splitter(filePath, number, this);
splitter.split();
}
virtual void DoProgress(float value) {
progressBar->setValue(value);
}
};

此时FileSplitter没有耦合任何一个界面类,就可以独立编译,在哪里都能支持进度通知。

但仍存在问题:不好支持多个通知。

要支持多个观察者,现在只支持一个观察者(MainForm或ProgressBar)。


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->setValue(value);
}
};

class ConsoleNotifier : public IProgress {
virtual void DoProgress(float value) {
cout << "." <<;
}
};

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 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.add(iprogress);
}
void removeIProgress(IProgress* iprogress){
m_iprogressList.remove(iprogress);
}
protected:
virtual void onProgress(float value){
List<IProgress*>::iterator it = m_iprogressList.begin();
while(it != m_iprogressList.end() ){
(*it)->DoProgress(value); // 更新进度条
it++;
}
}
};


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



Observer:IProgress Update:DoProgress Attach:addIProgress Detach:removeIProgress Notify:onProgress ConcreteSubject:FileSplitter
ConcreteObserver:MainForm和ConsoleNotifier
Observer和Subject是稳定的。下面具体的是变化的。


使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。

目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。

观察者自己决定是否需要订阅通知,目标对象对此一无所知。

Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。

相关推荐
qcx2315 小时前
Warp源码深度解析(二):自研GPU UI框架——WarpUI的ECH模式与渲染管线
人工智能·ui·设计模式·rust
qcx2316 小时前
Warp源码深度解析(三):Block-Based终端引擎——Grid模型、PTY与Shell Integration
人工智能·设计模式·架构·wrap
mounter62517 小时前
Linux Kernel Design Patterns (Part 2):从经典链表到现代 XArray,拆解内核复杂数据结构的设计哲学
linux·数据结构·链表·设计模式·内存管理·kernel
rrr217 小时前
【PyQt5】| 多线程设计模式
开发语言·qt·设计模式
SteveDraw17 小时前
常见的设计模式及工业场景下应用(更新中)
设计模式·c#·编码规范·gof23
ximu_polaris17 小时前
设计模式(C++)-行为型模式-状态模式
c++·设计模式·状态模式
ximu_polaris17 小时前
设计模式(C++)-行为型模式-迭代器模式
c++·设计模式·迭代器模式
huzhongqiang1 天前
Python 单例模式的几种实现方式:朴素才是王道
设计模式
一只叫煤球的猫1 天前
ThreadForge 1.2.0 发布:让 Java 并发代码更好写,这次补齐了高阶编排、示例与观测能力
java·设计模式·设计
软泡芙2 天前
【WPF 】MVVM 设计模式在 WPF 中的实战应用
设计模式·wpf