一、介绍:
此工具实现了观察者机制(同进程内交互)。
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);
}
}