Linux C++ 063-设计模式之观察者模式
本节关键字:Linux、C++、设计模式、观察者模式
相关库函数:
概念
观察者模式(有时又被称为发布/订阅模式)是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
实现方式
观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。
角色说明
观察者:(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
被观察者:被观察对象发生了某种变化(如图中的Some Change),从容器中得到所有注册过的观察者,将变化通知观察者。
撤销观察:观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。
实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
代码示例
// 定义一种一(被观察类)对多(观察类)的关系,让多个观察对象同时监听一个被观察对象,被观察对象状态发生变化时,会通知所有的观察对象,使他们能够更新自己的状态
// 观察者模式中存在两种角色:
// 观察者:内部包含被观察者对象,当被观察者对象的状态发生变化时,更新自己的状态(接收通知更新状态)
// 被观察者:内部包含了所有观察者对象,当状态发生变化时通知所有的观察者更新自己的状态(发送通知)
//
// 被观察者基类(内部存放了所有的观察者对象,以便状态发生变化时,给观察者发通知)
class Observer;
class Subject
{
protected:
list<Observer*> observers;
public:
string action; // 被观察者对象的状态
virtual void attach(Observer*) = 0;
virtual void detach(Observer*) = 0;
virtual void notify() = 0;
};
// 观察者基类 (内部实例化了被观察者的对象sub)
class Observer
{
protected:
string name;
Subject* sub;
public:
Observer(string name, Subject* sub) {
this->name = name;
this->sub = sub;
}
virtual void update() = 0;
};
class StockObserver : public Observer
{
public:
StockObserver(string name, Subject* sub) : Observer(name, sub)
{ }
void update() {
cout << name << "收到消息:" << sub->action << endl;
if (sub->action == "梁所长来了!") {
cout << "我马上关闭股票,装做很认真工作的样子!" << endl;
}
}
};
class NBAObserver :public Observer
{
public:
NBAObserver(string name, Subject* sub) : Observer(name, sub)
{ }
void update() {
cout << name << "收到消息:" << sub->action << endl;
if (sub->action == "梁所长来了!") {
cout << "我马上关闭NBA,装做很认真工作的样子!" << endl;
}
}
};
class Secretary : public Subject
{
void attach(Observer* observer) {
observers.push_back(observer);
}
void detach(Observer* observer) {
list<Observer*>::iterator iter = observers.begin();
while (iter != observers.end()) {
if ((*iter) == observer) {
observers.erase(iter);
return;
}
++iter;
}
}
void notify() {
list<Observer*>::iterator iter = observers.begin();
while (iter != observers.end()) {
(*iter)->update();
++iter;
}
}
};
int main_Observer()
{
Subject* dwq = new Secretary();
Observer* xs = new NBAObserver("xiaoshuai", dwq);
Observer* zy = new NBAObserver("zouyue", dwq);
Observer* lm = new StockObserver("limin", dwq);
dwq->attach(xs);
dwq->attach(zy);
dwq->attach(lm);
dwq->action = "去吃饭了!";
dwq->notify();
cout << endl;
dwq->action = "梁所长来了!";
dwq->notify();
return 0;
}
/* 运行结果:
xiaoshuai 收到消息:去吃饭了!
zouyue 收到消息:去吃饭了!
limin 收到消息:去吃饭了!
xiaoshuai 收到消息:梁所长来了!
我马上关闭NBA,装做很认真工作的样子!
zouyue 收到消息:梁所长来了!
我马上关闭NBA,装做很认真工作的样子!
limin 收到消息:梁所长来了!
我马上关闭股票,装做很认真工作的样子!
*/