C++11改进观察者模式
观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
先看一个简单的观察者模式是如何实现的:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
class Base
{
public:
Base(){}
virtual ~Base(){}
virtual void update(int a, int b) = 0;
};
class Devices1 : public Base
{
public:
virtual void update(int a, int b)
{
cout << "Devices1 " << a << "\t" << b << endl;
}
};
class Devices2 : public Base
{
public:
virtual void update(int a, int b)
{
cout << "Devices2 " << a << "\t" << b << endl;
}
};
class Subject
{
public:
void attach(int iKey, Base* pbase)
{
m_map[iKey] = pbase;
}
void detach(int iKey)
{
auto it = m_map.find(iKey);
if (it != m_map.end())
{
m_map.erase(it);
}
}
void notify(int a, int b)
{
auto it = m_map.begin();
while(it != m_map.end())
{
it->second->update(a, b);
it++;
}
}
private:
map<int, Base*> m_map;
};
int main()
{
Subject sub;
Devices1 d1;
Devices2 d2;
sub.attach(1, &d1);
sub.attach(2, &d2);
sub.notify(1, 2);
return 0;
}
这个例子很简单,是一种经典的观察者模式的实现,但是这种实现不够通用,只能对特定的观察者才有效,即必须是Base抽象类的派生类才行,并且这个观察者类还只能带2个int类型的参数。这种实现有两个限定:1、需要继承,继承是强对象关系,不够灵活;2、观察者被通知的接口参数不支持变化,导致观察者不能应付接口的变化。
我们可以通过C++11做一些改进,主要改进的地方有两个:通过被通知接口参数化和std::function来代替继承;通过可变参数模板和完美转发来消除接口变化产生新的影响。
使用C++11改良的观察者模式,代码如下所示:
#include <iostream>
#include <vector>
#include <map>
#include <functional>
#include <string>
using namespace std;
template<typename Func>
class Events
{
public:
Events(){};
~Events(){};
int Connect(Func&& f)
{
return Assign(f);
}
int Connect(const Func& f)
{
return Assign(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 Assign(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;
};
void print(int a, int b)
{
cout << "func " << a << ", " << b << endl;
}
class A
{
public:
void print(int a, int b)
{
cout << "class " << a << ", " << b << endl;
}
};
int main()
{
Events<std::function<void(int, int)>> myevent;
auto key = myevent.Connect(print);
A a;
std::function<void(int, int)> f = std::bind(&A::print, &a, std::placeholders::_1, std::placeholders::_1);
auto key1 = myevent.Connect(f);
///lambda注册
auto lamkey = myevent.Connect([](int a, int b){cout << "lambda " << a << ", " << b << endl;});
myevent.Notify(1, 2);
return 0;
}
C++11实现的观察者模式,内部维护了一个泛型函数列表,观察者只需要将观察者函数注册进来即可,消除了继承导致的强耦合。