欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

常见设计模式之(五):观察者模式

程序员文章站 2022-05-26 08:33:11
...

常见设计模式之(五):观察者模式

1 什么是观察者模式(observer pattern)?

1.1 定义

摘自 java 设计模式官网 中 有关观察者模式的定义:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically

翻译一下:
定义这样一种一对多的关系:当一个对象状态改变时,所有依赖这个对象的都会得到通知并且自动更新。

1.2 观察者模式中角色

角色 职责
被观察者(subject) 1. 动态地增加、取消观察者;2、发生改变时通知观察者 3、一般为抽象类
具体观察者(ConcreteSubject) 1. 实现自己的业务逻辑(比如说获取串口数据等)2、定义对哪些事件进行通知
观察者(Observer) 1、收到Update时,对收到的信息进行处理
具体观察者(ConcreteObserver) 1、对于不同的具体的观察者,对于信息的处理是不一样的 ,每个具体的观者都有自己的处理逻辑

2、观察者模式的c++实现

本博文先介绍观察者模式最简单模型,一般通用的类图如下:
常见设计模式之(五):观察者模式

c++源码如下:

AbstractSubject.h

#ifndef ABSTRACT_SUBJECT_H
#define ABSTRACT_SUBJECT_H
#include <stdio.h>
#include <vector>

#include "AbstractObserver.h"
class AbstractObserver;
class AbstractSubject
{
public :
    AbstractSubject()
    {

    }
    ~AbstractSubject()
    {

    }

    void add_observer(AbstractObserver * observer)
    {
        vec_observer.push_back(observer);
    }

    void delete_observer(AbstractObserver  * observer)
    {
        for(auto intor = vec_observer.begin();intor != vec_observer.end();intor++)
        {
            if(*intor == observer)
            {
                vec_observer.erase(intor);
            }
        }
    }

    void notify_all_observer(void)
    {
        for(auto intor = vec_observer.begin();intor != vec_observer.end();intor++)
        {
            (*intor) ->update();
        }
    }

private:
    std::vector< AbstractObserver *> vec_observer;

};

#endif

AbstractObserver.h

#ifndef ABSTRACT_OBSERVER_H
#define ABSTRACT_OBSERVER_H
#include <stdio.h>
#include <vector>

class AbstractObserver
{
public :
    AbstractObserver()
    {

    }
    ~AbstractObserver()
    {

    }
    virtual void update(void) = 0;
};

#endif

ConcreteSubject.h

#ifndef CONCRETE_SUBJECT_H
#define CONCRETE_SUBJECT_H
#include <stdio.h>

#include "AbstractSubject.h"

class ConcreteSubject : public AbstractSubject
{
public:
    ConcreteSubject()
    {

    }

    ~ConcreteSubject()
    {

    }
    void do_some_thing(void)
    {
        printf("ConcreteSubject %s %d \n",__FUNCTION__,__LINE__);
        notify_all_observer();  
    }
};
#endif

ConcreteObserver1.h

#ifndef CONCRETE_OBSERVER_1_H
#define CONCRETE_OBSERVER_1_H

#include "AbstractObserver.h"

class ConcreteObserver1 :public AbstractObserver
{
public:
    ConcreteObserver1()
    {

    }

    ~ConcreteObserver1()
    {

    }
    virtual void update(void) override
    {
        printf("%s %s %d \n",__FILE__,__FUNCTION__,__LINE__);
    }

};

#endif

ConcreteObserver2.h

#ifndef CONCRETE_OBSERVER_2_H
#define CONCRETE_OBSERVER_2_H

#include "AbstractObserver.h"

class ConcreteObserver2 :public AbstractObserver
{
public:
    ConcreteObserver2()
    {

    }

    ~ConcreteObserver2()
    {

    }
    virtual void update(void) override
    {
        printf("%s %s %d \n",__FILE__,__FUNCTION__,__LINE__);
    }

};

#endif

ConcreteObserver3.h

#ifndef CONCRETE_OBSERVER_3_H
#define CONCRETE_OBSERVER_3_H
#include "AbstractObserver.h"
class ConcreteObserver3 :public AbstractObserver
{
public:
    ConcreteObserver3()
    {
    }
    ~ConcreteObserver3()
    {
    }
    virtual void update(void) override
    {
        printf("%s %s %d \n",__FILE__,__FUNCTION__,__LINE__);
    }
};
#endif

ObserverClient.cpp

#include "AbstractSubject.h"
#include "AbstractObserver.h"

#include "ConcreteObserver1.h"
#include "ConcreteObserver2.h"
#include "ConcreteObserver3.h"

#include "ConcreteSubject.h"

int main(void)
{
    // 定义一个被观察者
    AbstractSubject * pcls_subject = new ConcreteSubject();
    // 定义三个观察者
    AbstractObserver * co1 = new ConcreteObserver1();
    AbstractObserver * co2 = new ConcreteObserver2();
    AbstractObserver * co3 = new ConcreteObserver3();
    //添加三个观察者
    pcls_subject->add_observer(co1);
    pcls_subject->add_observer(co2);
    pcls_subject->add_observer(co3);
    // 被观察者状态改变
    pcls_subject->notify_all_observer();

    pcls_subject->delete_observer(co2);

    pcls_subject->notify_all_observer();
    delete co1;
    delete co2;
    delete co3;
    delete pcls_subject;
}

编译并运行如下:

aaa@qq.com:/wan/06Observer# g++ -o ObserverClient ObserverClient.cpp -std=c++11 -g
aaa@qq.com:/wan/06Observer# ./ObserverClient
ConcreteObserver1.h update 22 
ConcreteObserver2.h update 22 
ConcreteObserver3.h update 22 
ConcreteObserver1.h update 22 
ConcreteObserver3.h update 22 

3 观察者模式的应用

3.1 观察者模式的注意事项

广播链问题

在观察者模式中一个观察者可以拥有双重身份,既是观察者,也是观察者,这就意味着:A -> B ->C 一旦建立这样的广播链,会造成程序负担。如果不慎就会广播风暴

程序效率

在存在多级触发时会存在程序的效率问题。

3.2 实际项目中具体应用

  • 文件系统 :比如说 我们建立了一个新文件,在建立文件的同时需要通知 磁盘管理 目录管理器等程序
  • 生活中的收音机
  • ATM机:当我们取完钱时:通知短信系统、余额更新系统等

4 观察者模式的扩展

4.1 项目中真实的观察模式

上述例子是非常原始的观察者模式,而在我们实际的项目中不会存在这样纯粹的模式,在系统设计中会对观察者中各个角色进行改造。

4.1.1 观者者和被观察者之间的沟通机制

被观察者状态改变会触发观察者的一个行为,同时会传递一个消息。这样就存在两个问题:如何通知给观者者,传递的消息的形式。

  1. 如何传递:
    观者和被观察者可以通过以下技术传递消息:消息队列、共享内存、管道、网络、硬件总线等,大家在进行系统设计时可以根据自己的情况进行选择。
  2. 消息传递格式:
    常见的消息格式有以下几种:json xml protobuf 自定义数据格式等。

4.1.2 观察者响应

观察者在既要接受被观察者传递过来的消息,同时还要处理相关消息,在观察者要处理N个被观察者传递过来的消息时,观察者就需要考虑自己的响应效率,一般两种方案:

1.空间换时间
采用缓存技术,准备好足够的空间来缓存消息,我先将消息缓存下来,然后自己慢慢处理,我只需要保证及时、快速地响应就可以了。
2.利用多线程技术
增加线程的数量,增强自己系统能力。

4.1.3 被观察者选择通知的人

在实际的项目中,存在这样问题,被观察者可能不需要传递给所有人,只需要传递给那些对消息感兴趣的的人,这点有点像网络中 广播 组播 单播 。被观察者自己决定传递给哪些人。做系统设计时需要考虑这个问题,保证架构的灵活性。

4.1.4 观察者和被观察者的扩展

首先是角色的变化:
双重身份的角色的存在。一个观察者同样也可以是被观察者。
数量的变化:
多个观察者 多个被观察者。

4.2 观者模式的终极boss (订阅-发布模式)

通过上面对观察者模式的扩展,最终扩展为订阅-发布的模式,想想生活中这样的例子太多了:手机消息的推送、公众号的订阅等等。在我们实际的开发中也存在一些订阅-发布模式的开源工具:比如说 mqtt zeromq nanomq等工具都支持订阅发布,在后续博文中我们将以mqtt为例来讲述订阅发布在实际项目中的应用。