观察者机制————利用回调函数实现

一、介绍:

此工具实现了观察者机制(同进程内交互)。

1.1、设计思路:
观察者与通知者以一个中介者交互。中介者以单例实现,因此观察者与通知者都可以接触到中介者。
观察者: 将其观察的主题与响应函数(作为回调函数)注册到中介者;
通知者: 建立主题类实例->将主题索引保存到中介者;查询出对应主题用于通知;
中介者: 对客户不可见,用于保存观察者、主题等数据;
主题: 通知主题及对应的内容->利用中介者仓库中获取数据通知。

1.2、此工具的优势:
1、客户不需要针对客户特性实现观察者、通知者类,是一个即拿即用的工具;
2、观察者与通知者互不持有对方的引用,不感知对方的存在,做到了解耦。

1.3、当前缺陷:
1、未加锁,不保证线程安全;
2、消息内容固定为int,未扩展:制约了回调函数与通知函数;
3、未考虑性能问题,只是玩具级工具;
4、未实现解观察detach()与释放主题release()两函数;

注:
1、以上缺陷只是待补充部分代码,不影响整个观察者机制的设计思想,待空了再修正。
2、本框架用到了之前编写的单例模式框架代码、宏声明构造函数等,全部代码见github仓

二、观察者机制框架类:

2.1、框架代码:

头文件:notifier_and_observer.h

// notifier_and_observer.h
// description: 观察者机制
// author: XXX
// date: XXX

#ifndef INCLUDE_TOOLS_NOTIFIER_AND_OBSERVER
#define INCLUDE_TOOLS_NOTIFIER_AND_OBSERVER

#include <iostream>
#include <atomic>
#include <utility>
#include <functional>
#include <vector>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include "class_register.h"

using subject_t = uint16_t;

// 主题用于发布主题对应信息
class subject_content
{
public:
    subject_content(subject_t subject) : subject_(subject) {}

    void notify(std::vector<int> content);

private:
    subject_t subject_;
};

// 通知者用于建立主题
class notifier
{
public:
    notifier() = default;

    DISALLOW_COPY_AND_ASSIGN(notifier);

    void build_subject(subject_t subject);

    std::shared_ptr<subject_content> query_subject(subject_t subject);
};

// 暂定回调函数入参为主题类型与值为int组成的vector,之后可扩展
using observer_cb_t = std::function<void(subject_t, std::vector<int>)>;

// 观察者用于观察主题
class observer
{
public:
    observer() = default;

    void attach(subject_t subject, observer_cb_t observer_cb);

    DISALLOW_COPY_AND_ASSIGN(observer);
};

// 中介者:用于通知者与观察者解耦,对客户不可见,保存两者数据。
class observer_container
{
public:
    using subject_cb_container_t = std::unordered_map<subject_t, std::vector<observer_cb_t>>;

    using subject_container_t = std::unordered_map<subject_t, std::shared_ptr<subject_content>>;

public:
    SINGLETON_CLASS(observer_container);

    void attach(subject_t subject, observer_cb_t observer_cb);

    void build_subject(subject_t subject);

    std::shared_ptr<subject_content> query_subject(subject_t subject);

    std::vector<observer_cb_t> query_observer(subject_t subject);

private:
    observer_container() = default;

private:
    subject_cb_container_t subject_cb_container;

    subject_container_t subject_container;
};

#endif

源文件:notifier_and_observer.cpp

// description: 观察者机制
// author: XXX
// date: XXX

#include "../../include/tools/notifier_and_observer.h"
#include <iostream>
#include <atomic>
#include <utility>
#include <functional>
#include <vector>

void subject_content::notify(std::vector<int> content)
{
    auto observer_cbs = observer_container::get_instance()->query_observer(subject_);
    for (auto &each : observer_cbs) {
        each(subject_, content);
    }
}

void observer::attach(subject_t subject, observer_cb_t observer_cb)
{
    observer_container::get_instance()->attach(subject, observer_cb);
}

void notifier::build_subject(subject_t subject)
{
    observer_container::get_instance()->build_subject(subject);
}

std::shared_ptr<subject_content>  notifier::query_subject(subject_t subject)
{
    return observer_container::get_instance()->query_subject(subject);
}

void observer_container::attach(subject_t subject, observer_cb_t observer_cb)
{
    // 主题未注册则观察失败
    if (subject_container.find(subject) == subject_container.end()) {
        std::cout << "subject: " << subject << " is not build" << std::endl;
        return;
    }

    // 主题注册后,再添加该主题的观察者
    auto subjectcb_iter = subject_cb_container.find(subject);
    if (subjectcb_iter == subject_cb_container.end()) {
        subject_cb_container[subject] = {observer_cb};
    } else {
        subjectcb_iter->second.push_back(observer_cb);
    }
    std::cout << "attach subject: " << subject << std::endl;

}

void observer_container::build_subject(subject_t subject)
{
    if (subject_container.find(subject) == subject_container.end()) {
        subject_container[subject] = std::make_shared<subject_content>(subject);
        std::cout << "build_subject: " << subject << std::endl;
        return;
    }
    std::cout << "subject: " << subject << "already build" << std::endl;
}

std::shared_ptr<subject_content> observer_container::query_subject(subject_t subject)
{
    auto subject_content_iter = subject_container.find(subject);
    if (subject_content_iter == subject_container.end()) {
        return nullptr;
    }
    return subject_content_iter->second;
}

std::vector<observer_cb_t> observer_container::query_observer(subject_t subject)
{
    auto subject_cb_iter = subject_cb_container.find(subject);
    return (subject_cb_iter == subject_cb_container.end()) ? std::vector<observer_cb_t>() : subject_cb_iter->second;
}

2.2、客户侧代码:

void cb1(subject_t subject, std::vector<int> message)
{
    std::cout << "cb1 receive notified message, subject  is: " << subject << " message is ";
    for (auto each : message) {
        std::cout << each << " ";
    }
    std::cout << std::endl;
}

void cb2(subject_t subject, std::vector<int> message)
{
    std::cout << "cb2 receive notified message, subject  is: " << subject << std::endl;
}

void test_notifier_and_observer()
{
    // 1、建立主题
    subject_t  theme =  1;
    notifier().build_subject(theme);
    // 2、观察主题
    observer().attach(theme, cb1);
    observer().attach(theme, cb2);

    // 3、通知主题
    {
        // 3.1、通知者定义通知的内容(之后可以用数据流,提升通知内容的扩展性)
        std::vector<int> message{1,2,3};

        // 3.2、通知者先查询主题是否存在:
        auto subject = notifier().query_subject(theme);
        if (subject ==  nullptr) {
            std::cout << "subject: " << theme << " not exist" << std::endl;
        }

        // 3.3、主题发布通知(之后可以将当前有无观察者信息体现在客户侧)
        subject->notify(message);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值