设计模式—观察者模式的快速指南。

观察者模式是一种非常常用的模式。实际上,它是如此普遍,以至于已被许多编程语言/库标准化。在Java中,它存在于java.util.Observer中(在Java 9中已弃用)。在Python中,它与apip install pattern-observer一样近。在C ++中,有时我们可以使用boost库,更确切地说是#include 。但是,它已作为定制解决方案在工业上广泛使用。为了能够正确使用它并了解其复杂性,我们需要深入研究它。

观察者模式被分类为行为设计模式。行为设计模式最具体地涉及类/对象之间的通信。 [由设计模式简单解释]

什么是观察者模式?除了广播模拟电视的步行监视器(如图)。该模式的目的是定义一对多关系,以便当一个对象更改状态时,其他对象将被通知并自动更新。更准确地说,它希望被告知系统中发生的事件。让我们通过三个步骤将难题的各个部分放在一起。

第1步-关键字

定义关键字是本系列快速指南中的秘诀。这种方法帮助我真正了解了设计模式,在我的脑海中对它们进行了硬编码,并理解了其他设计模式之间的差异。

  1. 主题:它被认为是信息,数据或业务逻辑的保持者。
  2. 注册/附加:观察者将自己注册到主题,因为他们希望在发生更改时得到通知。
  3. 事件:事件是主题的触发因素,因此所有观察者都可以得到通知。
  4. 通知:取决于实现方式,主题可以将信息“推”给观察者,或者,如果观察者需要主题的信息,则可以“拉”信息。
  5. 更新:观察者独立于其他观察者更新其状态,但是其状态可能会根据触发的事件而改变。

步骤2 —图表

让我们将此设计分为不同的类以简化此过程。

  • ConcreteObserver是包含特定于当前实例的信息的类。该更新函数由使用者的notify()操作调用。观察者根据其当前状态独立更新。
  • 观察者是具体观察者的父类。它包含一个主题实例。初始化观察者后,它会将自己注册/附加到主题。
  • Subject类具有一个列表或一组观察者。触发事件时,它将调用notify()操作,该操作将通过调用其所有更新函数循环遍历所有观察者。

第3步-示例代码

我建议从我的git仓库“ Andreas Poyias”或下面的代码段(按提供的顺序)中按类复制代码类,并将其粘贴到任何可用的在线C ++编辑器中,例如c ++ shell,jdoodle,onlineGDB并运行它观察输出。然后阅读下面的评论或说明。花点时间,仔细阅读(这意味着一分钟,而不是更少,而不是更多)。

示例:考虑一场足球比赛。许多支持者正在观看比赛。我们按年龄将支持者分为两类,年轻人和老人。当他们的球队进球时,支持者会根据他们的年龄和兴奋程度做出不同反应。
现在,让我们谈谈用于观察者模式的术语:

  • 游戏是主题,支持者是观察者。
  • 所有观察者都附加到/注册到该主题,并且在足球队得分时得到通知(触发事件是他们的队得分时)。
  • 观察者根据收到的通知更新其行为。

学科
对于此类,我们需要访问观察者列表。当观察者即将注册时,他们调用attach(this)函数将自己添加到可用列表中(这是观察者的实例)。当事件被触发时,我们wenotify()所有观察者独立地更新他们的状态。在此示例中,触发条件是观察者的足球队得分。

#include 
#include 
使用名称空间std;
类Subject {
    向量观察者;
    布尔得分; //触发事件
上市:
    //注册观察者
    无效的attach(观察者* obs){
        observers.push_back(obs);
    }
   
   //这是事件
   //设置if得分并通知所有观察者
   无效setScored(布尔分数){
      得分=得分;
      通知();
   }
bool getScored(){
      回报得分;
   }
   //通知实现进一步下降
   //,以便脚本编译并运行
   void notify();
};

观察者
此类取决于其注册的主题。当具体的观察者被初始化时,他们将自己附加到主题上。在此示例中,每个观察者的状态是他对游戏的兴奋程度。

类观察者
{
    主题* subj;
    int兴奋级别; //状态
  上市:
    观察者(Subject * mod,int excLevel)
    {
        subj = mod;
        excitementLevel = excLevel;
        //观察者向主题注册/附加
        subj-> attach(this);
    }
    虚拟void update()= 0;
  受保护的:
    主题* getSubject(){
       返回主题
    }
    setExcitementLevel(int excLevel){
       excitementLevel = excLevel;
    }
    int getExcitementLevel(){
       返回excitingLevel;
    }
};

这是Subject :: notify()声明,正如我们之前提到的,它的工作是通知所有观察者更新其状态。

无效Subject :: notify(){
  对于(int i = 0; i  update();
}

具体观察员
具体的观察者继承自Observer类,并且它们都必须具有更新功能。在此示例中,具体的观察者在新老支持者之间有所区别。如果他们的兴奋程度过高,年长的支持者就有心脏病发作的风险,而年轻的支持者有饮酒和开车的风险。它们的状态独立更新,正如我们将在下面的主要功能中证明的那样。

Old_ConcreteObserver类:公共观察员
{
   上市:
     //调用父构造函数向主题注册
     Old_ConcreteObserver(Subject * mod,int div)
        :观察员(mod,div){}
     //对于老年人,如果兴奋程度
     //超过150,他们有心脏病发作的风险
     无效update()
     {
        布尔得分= getSubject()-> getScored();
        setExcitementLevel(getExcitementLevel()+ 1);
        如果(得分&& getExcitementLevel()> 150)
        {
          cout <<“老观察员队得分!!”
               <<“他的兴奋程度是”
               << getExcitementLevel()
               <<“警惕心脏病发作!” << endl;
        }其他{
          cout <<“团队没有得分。Yeeeih不用担心”
               << endl;
        }
    } //结束update()
};
类Young_ConcreteObserver:公共观察员
{
   上市:
     //调用父构造函数向主题注册
     Young_ConcreteObserver(Subject * mod,int div)
       :观察员(mod,div){}
     //对于老年人,如果兴奋程度
     //超过100,他们就有心脏病发作的危险
     无效update()
     {
        布尔得分= getSubject()-> getScored();
        setExcitementLevel(getExcitementLevel()+ 1);
        如果(得分&& getExcitementLevel()> 100)
        {
          cout <<“年轻观察家的球队得分!”
               <<“他的兴奋程度是”
               << getExcitementLevel()
               <<“不要酒后驾车!!” << endl;
        }其他{
          cout <<“团队没有得分。没什么可担心的”
               << endl;
       }
    } //结束update()
};

主功能
具体的观察者将自己注册到Subject实例。他们的状态是兴奋程度,这是第二个参数。当事件被触发“ subj.setScored(true)”时,则调用Subject :: notify()更新注册的观察者。在下面的场景中,我们有三个观察员,youngObs1过度兴奋,有饮酒和开车的风险,oldObs1也过度兴奋,有其他危险(心脏病发作)。最终,年轻的ObsObs2还是年轻的,因为他没有过度兴奋,所以没有什么可担心的。

重要的是要注意,这三个观察者根据他们的状态(兴奋程度)和他们的类型(年轻人或老人)独立更新。
int main(){
   主题主题;
   Young_ConcreteObserver youngObs1(&subj,100);
   Old_ConcreteObserver oldObs1(&subj,150);
   Young_ConcreteObserver youngObs2(&subj,52);
   subj.setScored(true);
}
//输出
//年轻观察者队得分!!他的兴奋度是101
//不要酒后驾车!
//老观察者队得分!!他的兴奋度是151手表
//心脏病发作!球队没有得分。
//没什么可担心的

使用观察者模式有一些好处,而要采用这种模式则需要注意一些要点[学习Python设计模式]。

  • 观察者模式提供了一种设计,主体和观察者之间是松散耦合的。主题不需要了解ConcreteObserver类。可以在任何时间点添加任何新的观察者。添加新的观察者时,无需修改主题。观察者和主题之间并没有捆绑在一起,并且彼此独立,因此,主题或观察者的更改不会相互影响。
  • 没有组合选项,因为可以实例化Observer接口。
  • 如果观察者使用不当,则很容易增加复杂性并导致性能问题。
  • 通知可能不可靠,并可能导致比赛条件或不一致。

下一个博客将是Bridge设计模式的快速指南。这是一种结构设计模式,已在行业中广泛使用。不要忘记喜欢/拍我的博客文章并关注我的帐户。这让我感到满意,因为我帮助了一些开发人员并推动我继续写作。如果您想了解特定的设计模式,请告诉我,以便将来为您提供。

有关设计模式的其他快速指南:

  1. 设计模式—抽象工厂的快速指南。
  2. 设计模式—桥接模式的快速指南。
  3. 设计模式-生成器模式的快速指南。
  4. 设计模式-装饰模式的快速指南。
  5. 设计模式-外墙模式的快速指南。
  6. 设计模式-观察者模式快速指南。
  7. 设计模式-单例模式快速指南。