假设我们要设计一个交通状况监控系统,收到的数据封装成TrafficData类,然后把他拥堵状况用图形显示出来,处理该显示用TrafficMap类实现,然后又想以表格形式显示出来,那么用TrafficTable类实现。当TrafficData变更的时候,需要通知TrafficMap和TrafficTable更新他们的显示,一种直观的做法如下:
在TrafficData中分别添加TrafficTable和TrafficMap两个实例m_pTMap, m_pTTable作为成员。定义一个UpdateDisplay()函数,代码类似于:
TrafficData::UpdateDisplay()
{
m_pTMap->UpdateData(m_data);
m_pTTable->UpdateData(m_data);
}
现在,假如我们又想把交通状况朗读出来(用TrafficVoice类实现),则要在TrafficData中增加TrafficVoice成员, 并在UpdateDisplay()中添加代码。每次的需求变更导致了TrafficData的更改,不利于代码重用和扩展。我们怎么利用C++的抽象机制更好解决这个问题呢?这是就用到Observer模式。
我们平时订阅网上新闻时,服务端便把我加到他的用户列表中,我们就成为一个Observer。当有新的新闻,服务端会遍历用户列表,通知每一个Observer更新,这就是Observer模式的思想。现在,我们用Observer改进我们的设计。定义一个抽象基类叫 Subject, 定义一个纯虚函数UpdateDisplay()和一个Observer列表。 TrafficData从Subject继承,并实现UpdateDisplay()函数,代码如下:
class Subject {
vector<Observer*> m_observerlist; //Observer列表
virtual void UpdateDisplay() = 0;
void AddObserver( Observer* newMember); //添加观察者到列表
void RemoveObserver( Observer* member); //删除一个观察者
}
class TrafficData : public Subject {
virtual void UpdateDisplay() {
逐一通知m_observerlist中的每个成员,调用他们的UpdateData:
m_observerlist[i]->UpdateData( CData data);
}
}
在Observer抽象基类中定义UpdateData纯虚函数和Subject成员,然后TrafficMap, TrafficTable继承Subject, 代码如下:
class Observer {
Subject* m_pSubject;
virtual void UpdateData() = 0;
}
class TrafficMap : public Observer
{
virtual void UpdateData( CData data) {
data是最新数据,更新显示;
}
}
如果加入新的功能,如TrafficVoice把数据朗读出来,则只需要从Observer基类中继承,然后改写UpdateData就可以了,通过Subject类的AddObserver加入到列表中,每当数据有更新,则TrafficVoice类会被通知。
Observer类有效地降低了多个协作对象的耦合度(loose couple, 松耦合),有利于代码重用。特别是在大型,需求多变的工程中显得很有必要。实际上,MFC中的Document/View/Frame框架就是Observer模式的一个非常好的例子,他把数据和显示分离,由数据驱动视图的更新,详情可参考侯俊杰的<深入浅出MFC>。