1 观察者模式
- 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
- 定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
- 观察对象的状态发生变化时,通知给观察者。 观察者模式适用于根据对象状态进行相应处理的场景。
2 问题
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
| 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(){
for (int i = 0; i < m_fileNumber; i++){ float progressValue = m_fileNumber; progressValue = (i + 1) / progressValue; m_progressBar->setValue(progressValue); } } };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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(); } };
|
3 观察者v1
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
| 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 38
| class IProgress{ public: virtual void DoProgress(float value)=0; virtual ~IProgress(){} };
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); splitter.addIProgress(this); ConsoleNotifier cn; 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 << "."; } };
|
4 观察者v2(可执行)
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| #include "Header.h" #include <random> #include <thread>
class NumGen; class NumGenObserver { public: virtual ~NumGenObserver() {} virtual void update(NumGen *numGen) = 0; };
class NumGen { public: virtual ~NumGen() {} void addObserve(NumGenObserver *observe) { m_observeList.push_back(observe); } void deleteObserve(NumGenObserver *observe) { m_observeList.erase(std::remove(m_observeList.begin(), m_observeList.end(), observe)); } void notifyObverses() { for (auto gen : m_observeList) { gen->update(this); } } virtual int getNumber() = 0; virtual void execute() = 0;
private: std::vector<NumGenObserver *> m_observeList; };
class RandomNumGen : public NumGen { public: virtual int getNumber() override { return m_number; } virtual void execute() override { for (int i = 0; i < 20; ++i) { m_number = m_dis(m_gen); notifyObverses(); } }
private: std::random_device m_rd; std::mt19937 m_gen{ m_rd() }; std::uniform_int_distribution<int> m_dis{ 0, 100 }; int m_number{ 0 }; };
class DigitObserver : public NumGenObserver { public: virtual void update(NumGen *numGen) override { std::cout << "DigitObserver:"; std::cout << numGen->getNumber() << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } };
class GraphObserver : public NumGenObserver { public: virtual void update(NumGen *numGen) override { auto num = numGen->getNumber(); std::cout << "GraphObserver:"; for (int i = 0; i < num; ++i) { std::cout << "*"; } std::cout << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } };
int main() { NumGen *gen = new RandomNumGen; NumGenObserver *ob1 = new DigitObserver; NumGenObserver *ob2 = new GraphObserver; gen->addObserve(ob1); gen->addObserve(ob2); gen->execute(); delete gen; delete ob1; delete ob2; return 0; }
|
5 观察者v3(配合模板更通用的观察者模式)
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| template<typename ObserverType> class Subject { vector<ObserverType*> _list; public: void subscribe(ObserverType* obs) { auto itor = std::find(_list.begin(), _list.end(), obs); if (_list.end() == itor) { _list.push_back(obs); } } void unSubscribe(ObserverType* obs) { _list.erase(std::remove(_list.begin(), _list.end(), obs)); }
template<typename FuncType> void publish(FuncType func) { for (auto obs : _list) { func(obs); } } };
class CatObserver { public: virtual void onMiaow() = 0; virtual ~CatObserver() {} };
class Tom : public Subject<CatObserver> { public: void miaow() { cout << "喵" << endl; publish(std::bind(&CatObserver::onMiaow, std::placeholders::_1)); } };
class Jerry : public CatObserver { public: void onMiaow() override { RunAway(); } void RunAway() { cout << "那只笨又猫来了,快跑!" << endl; } };
int main() { Tom tom; Jerry jerry1, jerry2, jerry3;
tom.subscribe(&jerry1); tom.subscribe(&jerry2); tom.subscribe(&jerry3); tom.miaow(); }
|
输出结果: 1 2 3 4
| 喵 那只笨又猫来了,快跑! 那只笨又猫来了,快跑! 那只笨又猫来了,快跑!
|
6 总结
- 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
- 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
- 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
- Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。
7 参考