观察者模式

观察者模式的UML类图入下 :

解决的问题 :

  • 解耦,参考QT的信号槽机制

详细描述:

  • 一个通知者有一份观察者的名单,通知者状态改变时,去名单上通知所有的观察者

注意点:

  • 通常开发中update()方法的名字不是固定的,会很不方便,C#事件委托机制
  • c++中建议使用sigslotsigc++等信号槽库

例子:

  1. QT信号槽
  2. 前台小妹(通知者)发现老板回来,于是通知员工们(观察者们)把状态改变为“认真工作”状态
  3. 红外摄像头(通知者)发现温度变化,于是通知观察者们【告警窗口】,【警铃】,【日志记录】和【断电按钮】执行自己的动作

代码:

  1. 抽象通知者Subject.hpp

    • 拥有一个名单set<Observer*> obs,存所有要通知的人(观察者们)
    • 添加通知者函数,移除通知者函数
    • 更新状态函数,遍历所有观察者,执行他们的update()函数
        #ifndef _SUBJECT_H 
        #define _SUBJECT_H 
         
        #include "MajiaoObject.hpp" 
        #include "Observer.hpp"
        #include <set>
         
        class Subject : virtual public MajiaoObject { 
            public :  
                // 观察者列表
                set<Observer*> obs; 
                Subject() {  } 
                ~Subject() {  } 
                virtual Subject* addObserver(Observer* ob) {
                    this->obs.insert(ob);
                    return this;
                }
        
                virtual Subject* delObserver(Observer* ob) {
                    this->obs.erase(ob);
                    return this;
                }
        
                // 遍历所有观察者,并执行各自的更新操作
                virtual void notify(int status) {
                    for(set<Observer*>::const_iterator it = obs.begin(); it != obs.end(); it ++) {
                        (*it)->update(status);
                    }
                }
        }; 
        #endif	// _SUBJECT_H
      
  2. 抽象观察者Observer.hpp,拥有update()函数

    #ifndef _OBSERVER_H 
    #define _OBSERVER_H 
     
    #include "MajiaoObject.hpp" 
     
    class Observer : virtual public MajiaoObject { 
        public :  
            Observer() {  } 
            ~Observer() {  } 
            virtual void update(int status) { }
    }; 
    #endif	// _OBSERVER_H
    
  3. 具体通知者子类TempCamera.hpp,发现温度异常就去通知所有TempAlertWindow

    #ifndef _TEMPCAMERA_H 
    #define _TEMPCAMERA_H 
     
    #include "Subject.hpp" 
     
    class TempCamera : virtual public Subject { 
        public :  
            GET_SET(public, double, temp);
            double TEMP_LIMIT = 38.5;
    
            TempCamera() {  } 
            ~TempCamera() {  } 
    
            virtual void catchTemp() {
                if (temp > TEMP_LIMIT) {
                    int statusError = 1;
                    // 通知列表里的所有观察者
                    this->notify(statusError);
                }
            }
    }; 
    #endif	// _TEMPCAMERA_H
    
  4. 具体观察者TempAlertWindow.hpp,被通知时执行相应动作报警窗口变红色

    #ifndef _TEMPALERTWINDOW_H 
    #define _TEMPALERTWINDOW_H 
     
    #include "../AlertTemplate.hpp" 
    #include "../../Observer.hpp"
    #include <string.h>
    #include <string>
    using namespace std;
    
    // 这里产生了菱形继承问题,需要用virtual public解决
    class TempAlertWindow : virtual public AlertTemplate, virtual public Observer { 
        
            GET_SET(public, double, temp);
            GET_SET(public, int, windowColor);
    
            TempAlertWindow() {  } 
            ~TempAlertWindow() {  } 
    
            virtual void buildAlert() {
               this->alertMsg = "温度异常 ";
               this->alertMsg.append(to_string(this->temp));
               this->alertMsg.append(" 度"); 
            }
            virtual void sendAlert() { }
            virtual void callLeaders() { }
            virtual void closeAlert() { } 
            void windowRed() { this->windowColor = 0xFF0000; }
    
            virtual void update(int status) override {
                this->buildAlert();
                cout << this->getid() << "  " << this->alertMsg << endl;
            }
    }; 
    #endif	// _TEMPALERTWINDOW_H
    
  5. 使用sigslot库来模拟

    1. 模拟传感器发现温度异常,发出信号,日志对象接收信号,并执行动作
    2. 通知者需要一个成员变量sigslot::signal1<string> sig
      #ifndef _TEMPTRANSDUCER_H 
      #define _TEMPTRANSDUCER_H 
      
      #include "./sigslot/sigslot.h"
      #include "MajiaoObject.hpp" 
      
      class TempTransducer : virtual public MajiaoObject { 
          public :  
              // 使用sigslot库,只需要一个信号成员变量
              sigslot::signal1<string> sig;
      
              TempTransducer() {  } 
              ~TempTransducer() {  } 
      
              virtual void catchTemp() {
                  string str = "传感器 ";
                  str.append(to_string(this->getid())).append(" 发现温度异常");
                  this->sig.emit(str);
              }
      }; 
      #endif	// _TEMPTRANSDUCER_H
      
    3. 观察者方需要继承sigslot::has_slot<>,并且函数返回值是void,参数和信号方匹配
      #ifndef _ALERTLOGGER_H 
      #define _ALERTLOGGER_H 
       
      #include "../sigslot/sigslot.h"
      #include "../MajiaoObject.hpp" 
       
      // 这里如果虚继承sigslot::has_slots<>报错
      class AlertLogger : virtual public MajiaoObject, public sigslot::has_slots<> { 
          public :  
              AlertLogger() {  } 
              ~AlertLogger() {  }
      
              // 返回值是void,参数和信号方匹配
              virtual void log(string str) {
                  cout << "记录日志 " << str << endl;
              }
      }; 
      #endif	// _ALERTLOGGER_H
      
    4. main里,需要连接信号槽
      TempTransducer* tran = new TempTransducer();
      AlertLogger* logger2 = new AlertLogger(),
                 * logger3 = new AlertLogger();
      logger2->setid(2); 
      logger3->setid(3);
      
      // 绑定信号和槽
      tran->sig.connect(logger2, &AlertLogger::log);
      tran->sig.connect(logger3, &AlertLogger::log);
      // 发射信号
      tran->sig.emit("温度38度");
      tran->catchTemp();
      
原文地址:https://www.cnblogs.com/majiao61/p/15055676.html