设计模式-观察者模式

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模式的一个重要组成部分。

相关推荐
BD_Marathon18 小时前
设计模式——合成复用原则
设计模式·合成复用原则
书院门前细致的苹果1 天前
设计模式大全:单例、工厂模式、策略模式、责任链模式
设计模式·责任链模式·策略模式
BD_Marathon2 天前
设计模式——依赖倒转原则
java·开发语言·设计模式
BD_Marathon2 天前
设计模式——里氏替换原则
java·设计模式·里氏替换原则
jmxwzy2 天前
设计模式总结
设计模式
J_liaty2 天前
23种设计模式一代理模式
设计模式·代理模式
苏渡苇3 天前
优雅应对异常,从“try-catch堆砌”到“设计驱动”
java·后端·设计模式·学习方法·责任链模式
短剑重铸之日3 天前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
feasibility.3 天前
AI 编程助手进阶指南:从 Claude Code 到 OpenCode 的工程化经验总结
人工智能·经验分享·设计模式·自动化·agi·skills·opencode
BD_Marathon3 天前
七大设计原则介绍
设计模式