设计模式-观察者模式

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

相关推荐
总是难免1 小时前
设计模式 - 单例模式 - Tips
java·单例模式·设计模式
Java致死6 小时前
设计模式Java
java·开发语言·设计模式
ghost14318 小时前
C#学习第23天:面向对象设计模式
开发语言·学习·设计模式·c#
敲代码的 蜡笔小新1 天前
【行为型之迭代器模式】游戏开发实战——Unity高效集合遍历与场景管理的架构精髓
unity·设计模式·c#·迭代器模式
敲代码的 蜡笔小新2 天前
【行为型之命令模式】游戏开发实战——Unity可撤销系统与高级输入管理的架构秘钥
unity·设计模式·架构·命令模式
m0_555762902 天前
D-Pointer(Pimpl)设计模式(指向实现的指针)
设计模式
小Mie不吃饭2 天前
【23种设计模式】分类结构有哪些?
java·设计模式·设计规范
君鼎2 天前
C++设计模式——单例模式
c++·单例模式·设计模式
敲代码的 蜡笔小新2 天前
【行为型之中介者模式】游戏开发实战——Unity复杂系统协调与通信架构的核心秘诀
unity·设计模式·c#·中介者模式
令狐前生2 天前
设计模式学习整理
学习·设计模式