观察者模式
Model-View-Controller架构就是观察者模式的例子,C#中的Event委托也是使用的观察者模式
| ##### 进度条更新初阶版本 | 
下面样例产生了编译时的依赖(违背了抽象依赖细节)应该依赖抽象基类(MainForm与ProgressBar之间产生了依赖)
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
   | 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(){
          //1.读取大文件
          //2.分批次向小文件中写入         for (int i = 0; i < m_fileNumber; i++){             //...             float progressValue = m_fileNumber;             progressValue = (i + 1) / progressValue;             //更新进度条             //不能依赖实现细节             m_progressBar->setValue(progressValue);         }     }
      class MainForm : public Form {     TextBox* txtFilePath;     TextBox* txtFileNumber;     //依赖ProgressBar     ProgressBar* progressBar;
  public:     void Button1_Click(){
          string filePath = txtFilePath->getText();         int number = atoi(txtFileNumber->getText().c_str());
          FileSplitter splitter(filePath, number, progressBar);
          splitter.split();     } };
 
   |  
  | 
文件读取进度条更新观察者模式改进版本
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
   | //修改后,将progressbar抽象成接口,紧耦合变成松耦合,编译就不依赖progress //变成了良好的耦合,符合依赖倒置原则 //iprogress接口 class IProgress{ public:     virtual void DoProgress(float value)=0;     virtual ~IProgress(){} };
 
  //被观察对象拥有一个观察者对象的集合(相当于subject) class FileSplitter {     string m_filePath;     int m_fileNumber;     //改良:使支持多个观察者,加入vector 或者list等     List<IProgress*>  m_iprogressList; // 抽象通知机制,支持多个观察者      public:     FileSplitter(const string& filePath, int fileNumber) :         m_filePath(filePath),          m_fileNumber(fileNumber){     }
      void split(){         //1.读取大文件         //2.分批次向小文件中写入         for (int i = 0; i < m_fileNumber; i++){             //...             float progressValue = m_fileNumber;             progressValue = (i + 1) / progressValue;             onProgress(progressValue);//发送通知         }     }
      //原本列表初始化已经不适用,添加add和remove操作函数     void addIProgress(IProgress* iprogress){         m_iprogressList.push_back(iprogress);     }
      void removeIProgress(IProgress* iprogress){         m_iprogressList.remove(iprogress);     }
  //继续优化,protected下写onProgress,层次更清晰 protected:     //对于onprogress也需要改变     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 ConsoleNotifier : public IProgress { public:     virtual void DoProgress(float value){         cout << ".";     } };
 
  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);
      }     //重写DoProgress     virtual void DoProgress(float value){         progressBar->setValue(value);     } };
  |