2021-09-30


前言

最近在看ETH的开源库towr时,学习到一种多个类之间有意思的用法,称为观察者模式,在这里简要记录。


一、观察者模式是什么?

观察者模式中,定义了一种一对多的依赖关系,可以让多个观察者对象同时监听某一被观察者对象,一旦被观察者状态发生变化,则相应的观察者收到通知,并发生相应的变化.通俗来讲有点"发布–订阅"的意思.其中主要有四中类:
抽象被观察者类:提供维护一个将多个观察者聚集的方法,进行观察者的增加和删除
具体被观察者类:存储有关状态,并在状态变化时,给与其相关的观察者发出通知,进行更新
抽象观察者类:为具体观察者提供一个状态更新的接口
具体观察者类:根据自身情况更新状态(可以有多个)
一个具体被观察者类对应多个具体观察者,如下图所示.抽象被观察者类与观察类之间存在双向关联关系.

在这里插入图片描述

二、简单例子

在这里借用其他人的例子来解释下,具体怎么实现.这里定义一个北京时间类,当作被观察者对象;然后定义美国,巴黎等时间.实现北京时间改变的同时,美国和巴黎时间自动更新.

1.抽象观察者类

/*observer.h
 *首先定义一个观察者抽象类Observer,其中要声明有被观察者类Subject存在.
 */
#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

class Subject;    //声明存在一个Subject类

class Observer    //观察者 
{
public:
    virtual void update(Subject * subject) = 0; //为具体的观察者对象留的更新接口
    int _hour;
    int _min;
    int _sec;
    Subject * _subject; //相联系的被观察者  
};

2.抽象被观察者类

/*subject.h
 *定义被观察者抽象类Subject
 */
#include"observer.h"
class Subject   //被观察者
{
public:

    void addRegister(Observer * observer)  // 观察者注册,增加观察者
    {
        observerList.push_back(observer);
    }

    void delRegister(Observer * observer)  // 观察者取消,删除观察者
    {
        observerList.erase(find(observerList.begin(),observerList.end(),observer));
    }
    void notify()  //通知观察者进行更新
    {
        list<Observer*>::iterator itr;
        for(itr = observerList.begin(); itr != observerList.end(); ++itr)
        {
           (*itr)->update(this);
        }
    }

    int _hour;
    int _min;
    int _sec;
    list<Observer*>  observerList;  //注册后的观察者集合
};

3.具体被观察者和观察者类

/*spline.h
 *定义具体的被观察者和观察者
 */
 #include"observer.h"
 #include"subject.h"
 
class ChinaClock:public Subject  //被观察者子类 北京时间
{
public:
    void set(int hour, int min, int sec)
    {
        cout<<"China clock is set"<<endl;
        _hour = hour;
        _min = min;
        _sec = sec;
        notify();              //被观察者发出通知
    }
};
class AmericaClock:public Observer //观察者子类 美国时间
{
public:
    AmericaClock(Subject * subject)  //将自身与被观察者关联
    {
        _subject = subject;
        _subject->addRegister(this);
    }
    void update(Subject * subject)  //收到通知后进行相应的更新
    {

        _hour = subject->_hour;
        _min  = subject->_min;
        _sec  = subject->_sec;
        dis();

    }
    void dis()
    {
        cout<<"America clock is set"<<endl;
        cout<<"hour:"<<_hour<<"min:"<<_min<<"sec:"<<_sec<<endl;
    }

};

class LondenClock:public Observer //观察者子类 英国时间
{
public:
    LondenClock(Subject * subject)
    {
        _subject = subject;
        _subject->addRegister(this);
    }
    void update(Subject * subject)
    {
        _hour = subject->_hour;
        _min  = subject->_min;
        _sec  = subject->_sec;
        dis();

    }
    void dis()
    {
        cout<<"Londen clock is set"<<endl;
        cout<<"hour:"<<_hour<<"min:"<<_min<<"sec:"<<_sec<<endl;
    }
};

4.主函数

int main()
{
    ChinaClock   *cc  = new ChinaClock;       //创建北京时间被观察对象

    AmericaClock *ac  = new AmericaClock(cc); //创建美国时间观察对象
    LondenClock  *lc  = new LondenClock(cc);  //创建英国时间观察对象
    JapanClock   *jc  = new JapanClock(cc);   //创建日本时间观察对象

    cc->set(1,2,3);                           //改变被观察北京时间
    return 0;
}

三、总结

其中重要的部分主要有:1.在观察者的构造函数中需要以被观察指针为形参,建立两者的关联;2.被观察者中需要有通知观察者的方法.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值