经典的观察者模式
先看一下GOF的经典观察者模式,主题类Subject中包含的观察者的列表,并且提供attach、detach以及notify通知接口。通知后调用观察者的虚接口。
使用C++11改进
template<typename Func>
class Events
{
public:
//注册观察者
int connect(Func&& f)
{
return assgin(f);
}
//注册观察者
int connect(const Func& f)
{
return assgin(f);
}
//移除观察者
void disconnect(int key)
{
m_connections.erase(key);
}
//通知所有的观察者
template<typename ...Args>
void notify(Args...args)
{
for (auto& it : m_connections)
{
//入参传入所有的观察者,需要入参保存一致
it.second(std::forward<Args>(args)...);
}
}
private:
template<typename F>
int assgin(F &&f)
{
int k = m_observerId++;
m_connections.emplace(k, std::forward<F>(f));
return k;
}
int m_observerId = 0; //观察者号
std::map<int, Func> m_connections; //观察者列表
};
struct StA
{
int a, b;
void print(int a, int b)
{
cout << a << "," << b << endl;
}
};
void print(int a, int b)
{
cout << a << "," << b << endl;
}
int main()
{
Events<std::function<void(int, int)>> myevent;
//函数方式注册观察者
auto key = myevent.connect(print);
//lambda注册,修改对象数据
StA t;
auto lambdakey = myevent.connect([&t](int a, int b) {t.a = a; t.b = b; });
//functional
std::function<void(int, int)> f = std::bind(&StA::print, &t, std::placeholders::_1, std::placeholders::_2);
myevent.connect(f);
int a = 1, b = 2;
myevent.notify(a, b);
cout << t.a << "," << t.b << endl;
getchar();
return 0;
}
内部维护了一个泛型函数map表,这样就消除了继承导致的强耦合(需要注册的观察者对象都需要继承观察者虚基类),通知接口使用可变参数模板,消除接口变化的影响。
代码引自:深入应用C++11 代码优化与工程实践 8.2节