• 观察者模式


    观察者模式的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();
        
  • 相关阅读:
    工作中遇到的java 内存溢出,问题排查
    java线上内存溢出问题排查步骤
    性能测试-java内存溢出问题排查
    164 01 Android 零基础入门 03 Java常用工具类01 Java异常 04 使用try…catch…finally实现异常处理 04 终止finally执行的方法
    163 01 Android 零基础入门 03 Java常用工具类01 Java异常 04 使用try…catch…finally实现异常处理 03 使用多重catch结构处理异常
    162 01 Android 零基础入门 03 Java常用工具类01 Java异常 04 使用try…catch…finally实现异常处理 02 使用try-catch结构处理异常
    161 01 Android 零基础入门 03 Java常用工具类01 Java异常 04 使用try…catch…finally实现异常处理 01 try-catch-finally简介
    160 01 Android 零基础入门 03 Java常用工具类01 Java异常 03 异常处理简介 01 异常处理分类
    159 01 Android 零基础入门 03 Java常用工具类01 Java异常 02 异常概述 02 异常分类
    158 01 Android 零基础入门 03 Java常用工具类01 Java异常 02 异常概述 01 什么是异常?
  • 原文地址:https://www.cnblogs.com/majiao61/p/15055676.html
Copyright © 2020-2023  润新知