当对象间存在一对多的依赖关系时,当一个对象被修改时,则会自动通知所有依赖于它的对象。这种情况就可以使用观察者模式。本文的观察者模式消除了传统的观察者模式中观察者和主题的需要继承的强耦合关系,可以注册任意参数的函数,灵活性更高。
#include <unordered_map>
#include <string>
#include <functional>
#include <iostream>
template<typename Callable>
class Subject {
public:
Subject() : observer_id_{0} {}
~Subject() {}
int Attach(Callable&& f) {
return Add(f);
}
int Attach(const Callable& f) {
return Add(f);
}
int Remove(int key) {
return observers_.erase(key);
}
template<typename...Args>
std::unordered_map<int, int> Update(Args&&...args) {
std::unordered_map<int, int> rets;
for (auto const& observer : observers_) {
rets.emplace(observer.first,
observer.second(std::forward<Args>(args)...));
}
return rets;
}
private:
template<typename F>
int Add(F&& f) {
int ret = observer_id_;
observers_.emplace(ret, std::forward<F>(f));
++observer_id_;
return ret;
}
int observer_id_;
std::unordered_map<int, Callable> observers_;
};
class Task1 {
public:
int Add(const int a, const int b) {
std::cout << "do task1" << std::endl;
return a+b;
}
};
class Task2 {
public:
int operator()(const int a, const int b) {
std::cout << "do task2" << std::endl;
return a*b;
}
};
int main() {
Subject<std::function<int(int, int)>> subject;
Task1 task1;
auto task1_key = subject.Attach(
std::bind(&Task1::Add, &task1, std::placeholders::_1, std::placeholders::_2));
Task2 task2;
auto task2_key = subject.Attach(task2);
auto lambda_key = subject.Attach([](int a, int b){
std::cout << "do lambda" << std::endl;
return a -b;});
auto ret = subject.Update(10, 5);
std::cout << "task1 ret:" << ret[task1_key] << std::endl;
std::cout << "task2 ret:" << ret[task2_key] << std::endl;
std::cout << "lambda ret:" << ret[lambda_key] << std::endl;
subject.Remove(lambda_key);
subject.Update(10, 5);
return 0;
}
class内部成员observers_是一个unordered_map,用来保存观察者注册的消息,这个消息是一个泛型函数,可以通过key来找到对应的消息。这个key主要用来区分消息,实现保存消息的返回值以及移除消息。
在使用的时候,观察者只需要调用Attach将函数添加进来,同时保存key。添加的函数是可调用的类型,示例中使用了std::bind和成员函数有operator()的对象,以及lambda表达式。有更新的时候只需要调用Update即可执行所有注册的函数。