一、介绍:
此工具实现了观察者机制(同进程内交互)。
此工具的优势: 1、客户不需要针对客户特性实现观察者、通知者类,是一个即拿即用的工具; 2、观察者与通知者相互解耦。
当前缺陷: 1、未加锁,不保证线程安全; 2、消息内容固定为int,未扩展:制约了回调函数与通知函数; 3、未考虑性能问题,只是玩具级工具; 4、未实现解观察detach()与释放主题release()两函数;
注: 1、以上缺陷只是待补充部分代码,不影响整个观察者机制的设计思想,待空了再修正。 2、本框架用到了之前编写的单例模式框架代码、宏声明构造函数等,全部代码见github仓。
二、观察者机制框架类:
2.1、框架代码:
头文件:notifier_and_observer.h
#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);
};
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
#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()
{
subject_t theme = 1;
notifier().build_subject(theme);
observer().attach(theme, cb1);
observer().attach(theme, cb2);
{
std::vector<int> message{1,2,3};
auto subject = notifier().query_subject(theme);
if (subject == nullptr) {
std::cout << "subject: " << theme << " not exist" << std::endl;
}
subject->notify(message);
}
}
|