观察者模式
观察者模式是最常用的设计模式之一。观察者模式定义了一种一对多的关系,多个观察者同时监听一个主题对象,当主题对象改变的时候会通知所有观察者对象,被通知的观察者会自动更新。
经典的观察者模式:
class Observer;
// 主题对象
class Observable
{
public:
virtual ~Observable() {}
virtual void registerObserver(Observer* o);
virtual void unregisterObserver(Observer* o);
// 通知所有观察者
virtual void notifyObservers();
private:
list<Observer*> observers; // 观察者列表
};
// 观察者
class Observer
{
public:
virtual ~Observer() {}
virtual void update() = 0; // 收到通知后的动作
};
inline void Observable::registerObserver(Observer* o)
{
observers.push_back(o);
}
inline void Observable::unregisterObserver(Observer* o)
{
observers.remove(o);
}
Observable是主题对象,也就是被观察者,子类只要继承就可以了。Observable保存一个观察者(Observer)列表。主题首先调用registerObserver方法将一个观察者对象注册到观察者列表中。当主题对象状态改变并且需要通知观察者时,就调用notifyObservers方法通知所有观察者更新主题状态。当主题需要解除观察者的依赖时,调用unregisterObserver方法。
Observer是观察者对象,定义了一个update的纯虚函数,子类需要继承并实现这个函数。update是观察者的一个回调函数,主题状态发生改变通知观察者正是调用了这个函数。
Observable与Observer具有一定的耦合,通过通知-回调机制,在具体的使用过程中可以将耦合性降到最低。
struct A : public Observable
{
A (int i) : i_(i) {}
int i_;
};
struct B : public Observer
{
int i_;
B(boost::shared_ptr<A>& a) : a_(a)
{
a->registerObserver(this);
i_ = a->i_;
}
virtual void update()
{
if (a_ != NULL)
{
i_ = a_->i_;
}
}
private:
boost::shared_ptr<A> a_;
};
void test()
{
boost::shared_ptr<A> a(new A(10));
boost::shared_ptr<B> b(new B(a));
cout << b->i_ << endl;
a->i_ = 100;
a->notifyObservers();
cout << b->i_ << endl;
}
输出:
10
100
这个观察者模式存在一些不足,上面也提到过,观察者模式中主题和观察者具有一定的耦合性,也就是说一个对象的改变会影响另一个依赖的对象。例如,主题并不能确定每个观察者的指针是否有效,假如其中一些观察者在程序运行的过程中已经被释放了,调用到这些已经被释放的指针时,程序就会崩溃。代码如下:
void test()
{
boost::shared_ptr<A> a(new A(10));
B* b = new B(a);
delete b;
a->i_ = 100;
a->notifyObservers(); // 这里发生程序崩溃
}
因此使用的过程中需要有效的管理主题对象和观察者对象的生命期。