模式动机

为某些对象建立一种“通知依赖关系”,一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)自动的得到通知。(一对多关系)

伪代码实现1

  1. // MainForm.cpp
  2. // c++不推荐多继承,但推荐一个主继承,其他都是接口的形式
  3. class MainForm : public form, public IProgress
  4. {
  5. TextBox* txtFilePath;
  6. TextBox* txtFileNumber;
  7. ProgressBar* progressBar;
  8. public:
  9. void Button1_Click() {
  10. string filePath = txtFilePath->getText();
  11. int number = atoi(txtFileNumber->getText().c_str());
  12. FileSplitter splitter(filePath, number, this);
  13. splitter.split();
  14. }
  15. virtual void DoProgress(float value) {
  16. progressBar->setValue(value);
  17. }
  18. };
  1. // FileSplitter.cpp
  2. class IProgress
  3. {
  4. public:
  5. virtual void DoProgress(float value) = 0;
  6. virtual ~IProgress() {}
  7. };
  8. class FileSplitter
  9. {
  10. string m_filePath;
  11. int m_fileNumber;
  12. // ProgressBar* m_ProgressBar; // 具体的通知控件
  13. IProgress* m_iprogress; // 抽象的通知机制
  14. public:
  15. FileSplitter(const string& filePath, int fileNumber):
  16. m_filePath(filePath),
  17. m_fileNumber(fileNumber),
  18. m_iprogress(iprogress) {
  19. }
  20. void split() {
  21. // 1.读取大文件
  22. // 2.分批次向小文件中写入
  23. for(int i = 0; i < m_fileNumber; i++) {
  24. if(m_iprogress != nullptr) {
  25. float progressValue = m_fileNumber;
  26. progressValue = (i + 1) / ProgressValue;
  27. m_iprogress->DoProgress(progressValue); // 更新进度
  28. }
  29. }
  30. }
  31. };

伪代码实现2(支持多个观察者)

  1. // MainForm.cpp
  2. // c++不推荐多继承,但推荐一个主继承,其他都是接口的形式
  3. class MainForm : public form, public IProgress
  4. {
  5. TextBox* txtFilePath;
  6. TextBox* txtFileNumber;
  7. ProgressBar* progressBar;
  8. public:
  9. void Button1_Click() {
  10. string filePath = txtFilePath->getText();
  11. int number = atoi(txtFileNumber->getText().c_str());
  12. ConsoleNotifier cn;
  13. FileSplitter splitter(filePath, number);
  14. splitter.addIProgress(this);
  15. splitter.addIProgress(&cn);
  16. splitter.split();
  17. splitter.removeIProgress(this);
  18. }
  19. virtual void DoProgress(float value) {
  20. progressBar->setValue(value);
  21. }
  22. };
  23. class ConsoleNotifier : public IProgress
  24. {
  25. public
  26. virtual void DoProgress(float value) {
  27. cout << "...";
  28. }
  29. }
  1. // FileSplitter.cpp
  2. class IProgress
  3. {
  4. public:
  5. virtual void DoProgress(float value) = 0;
  6. virtual ~IProgress() {}
  7. };
  8. class FileSplitter
  9. {
  10. string m_filePath;
  11. int m_fileNumber;
  12. // ProgressBar* m_ProgressBar; // 具体的通知控件
  13. List<IProgress*> m_iprogressList; // 抽象的通知机制 (重点)支持多个观察者
  14. public:
  15. FileSplitter(const string& filePath, int fileNumber):
  16. m_filePath(filePath),
  17. m_fileNumber(fileNumber){
  18. }
  19. void addIProgress(IProgress* iprogress) {
  20. m_iprogressList.add(iprogress);
  21. }
  22. void removeIProgress(IProgress* iprogress) {
  23. m_iprogressList.remove(iprogress);
  24. }
  25. void split() {
  26. // 1.读取大文件
  27. // 2.分批次向小文件中写入
  28. for(int i = 0; i < m_fileNumber; i++) {
  29. // ...
  30. float progressValue = m_fileNumber;
  31. progressValue = (i + 1) / ProgressValue;
  32. onProgress(progressValue);
  33. }
  34. }
  35. protected:
  36. // 在某些框架中,甚至设计为virtual,供子类去改写
  37. void onProgress() {
  38. List<IProgress*>::Iterator itor = m_iprogressList.begin();
  39. while(itor != m_iprogressList.end())
  40. {
  41. m_iprogress->DoProgress(progressValue); // 更新进度
  42. }
  43. }
  44. };

要点总结

  • 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达到松耦合
  • 目标发送通知使,无需指定观察者,通知会自动传播
  • 观察者自己决定是否需要订阅通知,目标对象那个对象此一无所知
  • Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分