前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++设计模式 - 观察者模式

C++设计模式 - 观察者模式

作者头像
开源519
发布2021-12-27 08:40:05
4140
发布2021-12-27 08:40:05
举报
文章被收录于专栏:开源519

观察者模式

观察者模式是一种行为设计模式,主要用于实现一种订阅机制,可在目标事件发生变化时告知所有观察此事件的对象,使观察者做出对应的动作。通常是通过调用各观察者所提供的方法来实现。

UML类图

观察者模式

CObserver类,为观察者抽象类,为具体观察者定义标准接口:

  • Update() 用于更新自身行为,由具体主题调用。
  • GetName用于获取定义的字符,用于标识各个对象。

CSubject类,为主题抽象类,主要为具体的主题类定义标准的接口。主要接口:

  • Register(): 注册观察者
  • Unregister(): 注销指定观察者
  • Notify(): 通知所有观察者

CRadio类,具体的主题类(CSubject子类)。例:无线电。

  • 实现注册/注销观察当前主题的接口Register/Unregister,供观察者调用。
  • 实现通知接口Notify,用于主题发布时,通知所有的观察者。

**CInterphone、CPhone **类,具体的观察者类。例:对讲机、手机

  • 实现消息传递接口Update,供具体主题对象调用,用于通知主题内容。

场景列举

如上场景,现某处无线电在特定频道发出广播,所有关注此频道设备都会接收到此信号。

具体主题为Radio,其内部需要在主题发布时,通知所有观察者

代码语言:javascript
复制
class CRadio : public CSubject
{
public:
    CRadio()
    {
        mObserverList.clear();
    }

    ~CRadio()
    {

    }

    int Register(CObserver *pObsr)
    {
        if (nullptr != pObsr) {
            mObserverList.push_back(pObsr);
        } else {
            OBSERVER_LOGE("Register failed!\n");
            return -1;
        }

        return 0;    
    }

    int Unregister(CObserver *pObsr)
    {
        if (nullptr != pObsr) {
            mObserverList.remove(pObsr);
        } else {
            OBSERVER_LOGE("Unregister failed!\n");
            return -1;
        }

        return 0;
    }

    int Notify(void *pMsg)
    {
        list<CObserver *>::iterator it;
        SMsgTransfer *pGmsg = (SMsgTransfer *)pMsg;

        OBSERVER_LOG("Send radio: [0x%x] [%s]\n", pGmsg->type, pGmsg->buf);
        // loop: 向监听此事件的所有观察者发布主题
        for (it = mObserverList.begin(); it != mObserverList.end(); it++) {
            (*it)->Update(pMsg);
        }

        return 0;
    }

private:
    list <CObserver *> mObserverList;
};

具体观察者为可接收到此无线电的设备:手机、对讲机

代码语言:javascript
复制
/* 监听无线电的设备: 对讲机 */
class CInterphone : public CObserver
{
public:
    explicit CInterphone(string value) 
    {
        mName = value;
    }

    ~CInterphone()
    {

    }

    string GetName()
    {
        return mName;
    }

    int Update(void *pMsg)
    {
        SMsgTransfer *msg = (SMsgTransfer *)pMsg;
        OBSERVER_LOG("%s receive: [0x%x] [%s]\n", mName.c_str(), msg->type, msg->buf);
        return 0;
    }

private:
    string mName;
};

/* 监听无线电的设备: 手机 */
class CPhone : public CObserver
{
public:
    explicit CPhone(string value) 
    {
        mName = value;
    }

    ~CPhone()
    {

    }

    string GetName()
    {
        return mName;
    }

    int Update(void *pMsg)
    {
        if (pMsg != NULL)
        {
            SMsgTransfer *msg = (SMsgTransfer *)pMsg;
            OBSERVER_LOG("%s receive: [0x%x] [%s]\n", mName.c_str(), msg->type, msg->buf);
        } else {
            OBSERVER_LOG("%s receive messages cannot be resolved!\n", mName.c_str());
        }

        return 0;
    }

private:
    string mName;
};

客户端代码。使用Radio和设备形成应用场景

代码语言:javascript
复制
CRadio theRadio;
CPhone thePhoneUser1("Phone user1");
CPhone thePhoneUser2("Phone user2");
CInterphone theInterUser1("Interphone user1");

static int init()
{
    // 注册监听无线电的设备,可放在观察者类初始化内部
    theRadio.Register(&theInterUser1);
    theRadio.Register(&thePhoneUser1);
    theRadio.Register(&thePhoneUser2);

    return 0;
}

int main(int argc, char *argv[])
{
    init();

    // 发出SOS无线电
    OBSERVER_LOG("------------------------------------------\n");
    SMsgTransfer msg1 = {191519, "SOS"};
    theRadio.Notify(&msg1);

    OBSERVER_LOG("------------------------------------------\n");
    SMsgTransfer msg2 = {131313, "HELLO"};
    theRadio.Notify(&msg2);

    return 0;
}

输出:

代码语言:javascript
复制
$ ./a.out 
------------------------------------------
Send radio: [0x2ec1f] [SOS]
Interphone user1 receive: [0x2ec1f] [SOS]
Phone user1 receive: [0x2ec1f] [SOS]
Phone user2 receive: [0x2ec1f] [SOS]
------------------------------------------
Send radio: [0x200f1] [HELLO]
Interphone user1 receive: [0x200f1] [HELLO]
Phone user1 receive: [0x200f1] [HELLO]
Phone user2 receive: [0x200f1] [HELLO]

总结

  • 观察者将耦合转移到抽象类之间,实现耦合倒转,具体的实现类无需关注此耦合,只需要完成分内的工作即可。主题无需关注观察者的数量及行为,观察者也不需了解主题具体的逻辑。
  • 满足开闭原则,当需要新增新的观察者时,只需要增加具体的观察者类即可,无需修改原有代码。
  • 一般情况下,观察者会被应用于不同进程之间。例如,在电视机的系统中,电视需要待机。此时当发生待机动作时,所有需要在待机时做出相应动作的进程都需要关注待机事件(例:APP需要保存当前数据)。此场景下,待机就为主题,其他进程为观察者。且需要增加一个通知类来维护广播的机制,此类需要具备跨进程通信和观察者机制。
  • 当系统中许多实例或组件需要关注同一个事件时,可采用观察者模式。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源519 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 观察者模式
    • UML类图
      • 场景列举
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档