模式动机
为某些对象建立一种“通知依赖关系”,一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)自动的得到通知。(一对多关系)
伪代码实现1
// MainForm.cpp
// c++不推荐多继承,但推荐一个主继承,其他都是接口的形式
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.cpp
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):
m_filePath(filePath),
m_fileNumber(fileNumber),
m_iprogress(iprogress) {
}
void split() {
// 1.读取大文件
// 2.分批次向小文件中写入
for(int i = 0; i < m_fileNumber; i++) {
if(m_iprogress != nullptr) {
float progressValue = m_fileNumber;
progressValue = (i + 1) / ProgressValue;
m_iprogress->DoProgress(progressValue); // 更新进度
}
}
}
};
伪代码实现2(支持多个观察者)
// MainForm.cpp
// c++不推荐多继承,但推荐一个主继承,其他都是接口的形式
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 << "...";
}
}
// FileSplitter.cpp
class IProgress
{
public:
virtual void DoProgress(float value) = 0;
virtual ~IProgress() {}
};
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 addIProgress(IProgress* iprogress) {
m_iprogressList.add(iprogress);
}
void removeIProgress(IProgress* iprogress) {
m_iprogressList.remove(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() {
List<IProgress*>::Iterator itor = m_iprogressList.begin();
while(itor != m_iprogressList.end())
{
m_iprogress->DoProgress(progressValue); // 更新进度
}
}
};
要点总结
- 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达到松耦合
- 目标发送通知使,无需指定观察者,通知会自动传播
- 观察者自己决定是否需要订阅通知,目标对象那个对象此一无所知
- Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分