设计模式基础(3):观察者模式
介绍观察者模式的C++示例代码、面向的问题、图解观察者模式核心思想
面向的需求
在一些软件的需求中需要多个对象之间建立一种“通知依赖关系”。即一个对象(被观察者)有变化,所有的依赖对象(观察者对象)都将得到通知。也可以说是通知-订阅模式。被观察者和观察者之间如果连接的过于紧密(一个变化,全体都需要变化)。那么就是应对变化的能力较差。
可以采用面向对象的技术,弱化具体联系,抽象其关系,利用抽象类来松耦合观察者与被观察者。
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| 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(){
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++; } } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| 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 { public: virtual void DoProgress(float value){ cout << "."; } };
|
分析代码及思想
程序的功能是:在分割文件时,显示文件分割的进度。分割函数(被观察者)中这个进度(事件)需要通知到界面和控制台(观察者)。
- 紧耦合的做法是,直接传参一个显示控件到分割函数中,得到进度并显示。但是此时,分割函数和界面均需要变化。
- 松耦合则是先抽象一个IProgress类,之后在分割函数中维护一个IProgress集合,并且动态维护。当发生事件时,逐个通知集合中的抽象类IProgress,抽象类中设计一个虚响应函数,每个需要接收信号的类,继承该抽象类并复写(override)这个响应函数,实现自身面对信号的响应。主要注意的是,将自身加入到动态维护的集合中。
关键点总结
- 使用面向对象的抽象,Observer模式使得目标者和观察者达到松耦合,自身改变,不会影响对方。
- 目标发送通知时,无需指定观察者,通知会自动传播。
- 观察者自己决定是否需要订阅通知,目标对象不必知道。
图解观察者模式
