设计模式 -- 深入探究观察者模式及源码实现(C++)

认识观察者模式

顾名思义, 所谓观察者模式, 既存在观察者必然存在被观察的对象。那么被观察的对象称之为主题, 即观察主题。 那么主题对象将对观察者进行管理。而观察者决定对什么主题感兴趣, 从而进行订阅, 同时可以取消订阅。

简单的说, 观察者模式中存在两个对象, 一个是主题对象, 一个是观察者对象。 而观察者对象通常为多个, 所以主题对象与观察者通常为“一对多”的关系。

应用场景

生活中,常见类似观察者模式的应用类似于:

  • 报社或者杂志的出版方和订阅者。出版方为主题对象, 订阅者为观察者
  • 收音机。 其中电台为主题对象, 而使用收音机的你为观察对象。
  • 天气预报。 气象台为主题对象,查看天气预报的对象为观察者。
  • 其他不胜枚举

凡是在一个场景中, 存在主题对象, 且存在观察者时。 请使用此设计模式。

实例及分析

本实例中, 直接拿订阅杂志作为实例讲解。订阅者为观察者, 杂志出版方为主题对象。 一旦订阅者订阅了杂志, 杂志发布方将定期向订阅者邮寄杂志。

下面我们站在各对象的角度进行实例分析。

对于杂志出版方, 他需要了解的信息是:

  • 订阅者列表
  • 订阅者都有一个地址(即接收订阅的接口)

出版方利用订阅者的地址进行杂志邮寄 ,即主题发布。 这是他唯一需要知道的。

而对于订阅者:

  • 杂志的内容
  • 订阅及取消订阅的方式

而订阅者关心的是杂志的内容, 因为杂志的内容而产生订阅的想法, 进而利用订阅的渠道(接口)进行杂志订阅。 同时, 当订阅者对杂志不再感兴趣, 再利用取消订阅渠道进行杂志退订。

另一种场景, 即杂志订阅者主动索取杂志, 而不是由杂志出版方或销售方进行杂志发布。即转被动变为主动。 这是观察者模式另一种的工作模式。

类设计

下面为一个基本的观察者模式:
<abstract>Subject - vecObservers: vector<Observer> + Notify(strState) + AddObserver() + RemoveObserver() <interface>Observer + Update(strState) ConcreteSubject + Notify(strState) ConcreteObserver + Update(strState)

下面为针对杂志订阅而设计的类图:
<interface>IMagazinePublisher - vecObservers: vector<subscriber> + Notify(strState) + AddObserver() + RemoveObserver() <interface>ISubscriber + Update(strState) CMagazinePublisher + Notify(strState) CSubscriberA + CSubscriberA(publisher) + Update(strState) CSubscriberB + CSubscriberB(publisher) + Update(strState)

源码实现

#include <iostream>
#include <set>
#include <string>


template <typename TData, typename ...Args>
class ISubject;

template <typename TData, typename ...Args>
class IObserver
{
public:
    virtual ~IObserver() = default;
public:
    explicit IObserver(ISubject<TData, Args...>* subject)
    {
        subject->AddObserver(this);
    }

    virtual void Update(const TData& param, const Args& ...args) const = 0;
};


template <typename TData, typename ...Args>
class ISubject
{
public:
    virtual ~ISubject() = default;

    typedef IObserver<TData, Args...> TObserver;
public:
    virtual void Notify(TData param, Args&&... args) const
    {
        for (auto& observer : _setObservers)
        {
            observer->Update(param, std::forward<Args>(args)...);
        }
    }


    virtual bool AddObserver(TObserver* observer)
    {
        return _setObservers.insert(observer).second;
    }


    virtual void RemoveObserver(TObserver* observer)
    {
        auto iterFind = _setObservers.find(observer);
        if (iterFind != _setObservers.end()){
            _setObservers.erase(iterFind);
        }
    }

private:
    std::set<TObserver*> _setObservers;
};


typedef ISubject<std::string> IMagazinePublisher;
typedef IMagazinePublisher::TObserver ISubscriber;

class CSubscriberA : public ISubscriber
{
public:
    explicit CSubscriberA(IMagazinePublisher* subject)
    : ISubscriber(subject)
    {
       
    }

    virtual void Update(const std::string& magazine) const override
    {
        std::cout <<typeid(*this).name() << " receive magazine: " <<magazine.c_str() << std::endl;
    }
};

class CSubscriberB : public ISubscriber
{
public:
    explicit CSubscriberB(IMagazinePublisher* subject)
    : ISubscriber(subject)
    {
       
    }

    virtual void Update(const std::string& magazine) const override
    {
        std::cout <<typeid(*this).name() << " receive magazine: " <<magazine.c_str() << std::endl;
    }
};



int main(int argc, char const *argv[])
{
    IMagazinePublisher magazineSubject;

    CSubscriberA observerA(&magazineSubject);
    CSubscriberB observerB(&magazineSubject);
    magazineSubject.Notify("人民司法");
    return 0;
}


/*
输出:
class CSubscriberB receive magazine: 人民司法
class CSubscriberA receive magazine: 人民司法
*/

总结

终归, 观察模式中, 存在两个场景:

  1. 主题对象对主题信息进行发布, 而观察者仅仅被动接收主题对象发布的信息。
  2. 观察者主动索取主题信息, 主题对象提供最新主题信息予以观察者。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值