观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式,它是对象行为型模式。
观察者模式是一种对象行为型模式,其主要优点如下。
1 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
2 目标与观察者之间建立了一套触发机制。
它的主要缺点如下。
1 目标与观察者之间的依赖关系并没有完全解除。
2 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
类图如下:
一个简单的观察者模式如下:
class Subject;
// 观察者接口类
class Observer
{
public:
virtual ~Observer();
// 即类图中Response函数
virtual void Update(Subject* theChangedSubject) = 0;
protected:
// 只有子类内部的其他函数可以调用protected函数
Observer();
};
// 目标接口类
class Subject {
public:
virtual ~Subject();
virtual void Attach(Observer*);
virtual void Detach(Observer*);
virtual void Notify();
protected:
Subject();
private:
// 观察者列表
List<Observer*> _observers;
};
// 增加观察者
void Subject::Attach(Observer* o) {
_observers->append(o);
}
// 删除观察者
void Subject::Detach(Observer* o) {
_observers->remove(o);
}
// 目标类发出通知,通知所有观察者
void Subject::Notify() {
ListIterator<Observer*> i(_observers);
for(i.first();!i.isDone();i.next()) {
i.currentItem()->Update(this);
}
}
这种实现方式主要两个限定:
(1)需要继承,继承是强对象关系,不够灵活
(2)观察者被通知的接口参数不支持变化(Observer的Update接口)
C++11改进有两点:
(1)通过std::fucntion来代替继承
(2)通过可变参数模板使得被通知接口参数化
C++11提供了default和delete,使我们可以方便地实现一个NonCopyable类。如果希望类不被复制,则直接从这个NonCopyable类派生。
NonCopyable类的实现:
class NonCopyable
{
protected:
// 将函数声明为显示构造函数
NonCopyable() = default;
~NonCopyable() = default;
// 禁止复制构造
NonCopyable(const NonCopyable&) = delete;
// 禁止赋值
NonCopyable& operator = (const NonCopyable&) = delete;
};
C++11改进后的观察者模式:
#include <iostream>
#include <string>
#include <functional>
#include <map>
using namespace std;
template<typename Func>
class Events : NonCopyable
{
public:
Events();
~Events();
// 注册观察者,支持右值引用
int Connect(Func&& f)
{
return Assign(f);
}
// 注册观察者
int Connect(const Func& f)
{
return Assign(f);
}
// 移除观察者
int 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;
};
测试代码如下:
struct stA
{
int a, b;
void print(int a,int b)
{
cout << "a," << a << " b," << b << endl;
}
};
void print(int a, int b)
{
cout << "a:" << a << " b:" << 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;});
// std::function注册观察者
std::function<void(int,int)> f = std::bind(&stA::print, &t,
std::placeholders::_1, std::placeholders::_2);
auto funckey = myevent.Connect(f);
int a=1,b=2;
// 广播所有观察者
myevent.Notify(a,b);
// 移除观察者
myevent.Disconnect(key);
myevent.Disconnect(lambdakey);
myevent.Disconnect(funckey);
return 0;
}
C++11改进后的观察者模式,内部维护了一个泛型函数map(m_connections),观察者只需将观察者函数注册进来,消除了继承导致的强耦合;也不要求观察者必须从某个类派生,当需要不同的观察者时,只需定义一个新的event即可。同时,通知接口使用了可变参数列表(Notify),支持任意参数。
参考网址: