本文是学习刘伟技术博客和《设计模式-可复用面向对象软件的基础》笔记,博客链接:http://blog.csdn.net/lovelion/article/details/17517213
主要是对博客和书本做提炼和记录,更多是对设计模式的基础框架学习,细节将略去,侧重对每个设计模式框架的理解。
我应该理解和掌握的:
1)能够画出这个设计模式的架构框图;
2)能够根据架构框图写出对应的伪代码;
3)这个模式的应用场景,主要优缺点。
1.观察者模式
假设我们有一份excel数据资料,改变数据的时候,它所表示的柱状图和棒状图都发生相应的改变。因此数据对象的任何状态改变都应该立即通知他们。观察者模式描述了如何建立这种关系。这一模式的关键是目标和观察者。一个目标可以有任意数目的观察者,一旦目标的状态发生改变,所有观察者都会得到通知。
(1)定义
观察者模式:定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖他的对象都得到通知并被自动更新。又称发布-订阅模式;也叫模型-视图(Model-View)、依赖(Dependents)。
1) 观察者模式结构图
2) 参与者
a) Subject(目标):
--目标通知他的观察者,可以有任意多个观察者。
--提供注册和删除观察者的接口。
b) Observer(观察者):为那些在目标发生改变时需获取通知的对象定义一个更新接口。
c) ConcreteSubject(具体目标):
--将有关状态存入各ConcreteObserver对象。
--当他的状态发生改变时,向他的各个观察者发出通知。
d) ConcreteObserver(具体观察者):
--维护一个指向ConcreteSubject对象的引用。
--存储有关状态,这些状态应当与目标的状态保持一致。
--实现Observer的更新接口以使自身状态与目标状态保持一致。
3) 看图写代码
/*
** FileName : ObserverPattern
** Author : lin005
** Date : 2015/02/09
** Description : More information, please go to http://blog.csdn.net/amd123456789
*/
#include<list>
using namespace std;
class Observer;
//抽象目标类
class Subject
{
public:
virtual void attach(Observer*) = 0;//添加观察者
virtual void detach(Observer*) = 0;//删除观察者
virtual void Notify() = 0;//通知观察者
virtual void setState(int s) = 0; //设置状态值
virtual int getState() = 0;
};
//抽象观察者
class Observer
{
public:
virtual void update() = 0;//更新状态值
virtual void setSubject(Subject* sj) = 0;//保持目标对象
};
//具体观察者
class ConcreteObserverA : public Observer
{
public:
ConcreteObserverA():s(NULL),state(0){}
//根据目标状态,改变自身状态
void update()
{
bool ret = (s->getState() == state);
cout<<"ConcreteObserverA is called"<<endl;
cout<<"(subject->state == A->state) = "<<ret<<endl;
if(!ret)
{
cout<<"now update A state"<<endl;
state = s->getState();
}
}
void setSubject(Subject* sj)
{
s = sj;
}
private:
Subject* s;
int state;
};
//具体观察者
class ConcreteObserverB : public Observer
{
public:
ConcreteObserverB():s(NULL),state(0){}
void update()
{
bool ret = (s->getState() == state);
cout<<"ConcreteObserverB is called"<<endl;
cout<<"(subject->state == B->state) = "<<ret<<endl;
if(!ret)
{
cout<<"now update B state"<<endl;
state = s->getState();
}
}
void setSubject(Subject* sj)
{
s = sj;
}
private:
Subject* s;
int state;
};
//具体目标类
class ConcreteSubject : public Subject
{
public:
ConcreteSubject():p_list(NULL),state(0){}
void attach(Observer* o)
{
p_list.push_back(o);
}
void detach(Observer* o)
{
p_list.remove(o);
}
void Notify()
{
list<Observer*>::iterator it = p_list.begin();
while(it != p_list.end())
{
(*it)->update();
++it;
}
}
//改变状态值,并通知观察者对象
void setState(int s)
{
state = s;
Notify();
}
int getState()
{
return state;
}
private:
list<Observer*> p_list;//持有观察者列表
int state;//目标对象的数据,发生改变便会通知观察者
};
//客户端测试
int main()
{
//创建两个观察者
Observer* A = new ConcreteObserverA();
Observer* B = new ConcreteObserverB();
//创建目标对象
Subject* S = new ConcreteSubject();
//观察者注入目标对象
A->setSubject(S);
B->setSubject(S);
//增加观察者
S->attach(A);
S->attach(B);
//目标数据发生改变
S->setState(2);
S->setState(3);
return 0;
}
(2)总结
1) 优点
a) 目标与观察者间的抽象耦合。目标只要维持一个抽象观察者集合,不知道任一个观察者属于哪一个具体类,这样他们之间的耦合是抽象的也是最小的。一个处于较低层次的目标对象可与一个处于较高层次的观察者通信并通知他,这样就保持了系统层次的完整性。
b) 支持广播通信。目标向所有的注册观察者发送通知,简化了一对多系统设计的难度。
c) 符合开闭原则,增加新的观察者无需修改原有代码。
d) 可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。
2) 缺点
a) 如果一个观察者对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间。
b) 意外的更新。没有相应的机制让观察者知道所观察的目标怎么发生变化,而仅仅知道观察目标发生了变化。如果依赖准则的定义或维护不当,常常会引起错误的更新。
(3)适用场景
1)当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中以使他们可以各自独立的改变和复用。
2)当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
3)当一个对象必须通知其他对象,而他又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的。