模式动机
为某些对象建立一种“通知依赖关系”,一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)自动的得到通知。(一对多关系)
伪代码实现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.cppclass 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.cppclass 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模式的一个重要组成部分
