III 行为模式(11)
Template
Strategy
State
Observer
Memento
Mediator
Command
Visitor
Chain of Responsibility
Iterator
Interpreter
1,Template(模板模式)
这样的情况:某一算法在不同的模块中有不同的实现细节,这时,将算法框架放在一个抽象基类中,然后派生这个基类,各派生类根据各自的需要来实现算法细节.这就是Template模式.
Strategy模式解决的是和Template模式类似的问题,但是Strategy模式是将算法封装到一个类中,并采取组合的方式解决这个问题。
class AbsCls
{
public:
virtual void TemplateMethod()=0;
protected:
virtual void Op1()=0;
virtual void Op2()=0; //Op1,Op2构成算法TemplateMethod框架,放在抽象类AbsCls中
};
class ConcreateCls_A:public AbsCls
{
public:
void TemplateMethod(){ this->Op1(); this->Op2(); }//实现细节
protected:
void Op1(){ cout<<"ConcreateCls_A::Op1/n"; }//原子实现
void Op2(){ cout<<"ConcreateCls_A::Op2/n"; }
};
class ConcreateCls_B:public AbsCls
{
public:
void TemplateMethod(){ this->Op1(); this->Op2(); }//实现细节
protected:
void Op1(){ cout<<"ConcreateCls_B::Op1/n"; }
void Op2(){ cout<<"ConcreateCls_B::Op2/n"; }
};
int main()
{
AbsCls*pObjA=new ConcreateCls_A;
pObjA->TemplateMethod();
AbsCls*pObjB=new ConcreateCls_B;
pObjB->TemplateMethod();
return 0;
}
上面说的Template模式的缺陷,这里用Strategy模式,采用”组合”的方式克服了这一缺陷. 下图中的Althrimlnterface是一个比上图中还要抽象的框架,可以理解为,除了表明它是”算法”之外,再无更具体的东西,不像上面的,知道它是算法,还知道它有Op1,Op2两个原子算法组成. 在ConcreateStra_A/B中,实现的AlthrimInterface是彻头彻尾两个不同的算法, 也就是说,在Strategy模式中,实现了多个算法.
class Strategy
{
public:
virtual void AlgrithmInterface()=0;
};
class ConcreateStrategy_A:public Strategy
{
public:
void AlgrithmInterface(){ cout<<"ConcreateStrategy_A::AlgrithmInterface/n"; }
};
class ConcreateStrategy_B:public Strategy
{
public:
void AlgrithmInterface(){ cout<<"ConcreateStrategy_B::AlgrithmInterface/n"; }
};
class Context
{
public:
Context(Strategy*pSt):_pSt(pSt){}
void DoTheJob(){ _pSt->AlgrithmInterface(); } //DoTheJob才是封装的算法框架
private: //其实现依赖于Stragegy子类的组合实现
Strategy*_pSt;
};
int main()
{
Strategy* pSt_A=new ConcreateStrategy_A;
Context* pCon_A=new Context(pSt_A);
pCon_A->DoTheJob();
Strategy* pSt_B=new ConcreateStrategy_B;
Context* pCon_B=new Context(pSt_B);
pCon_B->DoTheJob();
return 0;
}
3,State (状态机模式)
State模式与Strategy模式有点相似,但它强调的是”在不同状态下采取不同的动作”,如果不用State模式,则很可能会用到一组switch/case 语句,State克服了这一缺陷.克服的方法在下图中的那句注释中,下面的实现中只用了A,B两种状态,其实可有任意多种,添加ConcreateState_X就是了,然后在其Handle实现中,将Context的状态改成你想要的状态即可.
State模式注重的是什么状态下采取什么动作, 如下面的 ConcreateState_A::Handle的实现可以看出,在ConcreateState_A状态下,采取的动作将是打印出” ConcreateState_A::Handle”字串, 然后将状态改变为ConcreateState_B.
class Context;
class State //状态类
{
public:
virtual void Handle(Context*pCon)=0;//实际上用于改变Context的状态
};
class ConcreateState_A:public State
{
public:
void Handle(Context*pCon);
};
class ConcreateState_B:public State
{
public:
void Handle(Context*pCon);
};
class Context
{
public:
State* GetState(){ return _pSt; }//得到状态
void SetState(State*pSt){ _pSt=pSt; }//设置状态,实际上是将对象的指针SetState了
void Operation(){ _pSt->Handle(this); }//操作,调用State的函数
private:
State* _pSt;
};
void ConcreateState_A::Handle(Context*pCon)
{
cout<<"ConcreateState_A::Handle/n"; //具体操作
if (pCon->GetState()) //如果当前状态指针不为NULL,则改变状态为B
{
pCon->SetState(NULL);
}
pCon->SetState(new ConcreateState_B);
}
void ConcreateState_B::Handle(Context*pCon)//具体操作
{
cout<<"ConcreateState_B::Handle/n"; //如果当前状态指针不为NULL,则改变状态为A
if (pCon->GetState())
{
pCon->SetState(NULL);
}
pCon->SetState(new ConcreateState_A);
}
int main()
{
State*pSt_A=new ConcreateState_A;
Context* pCon=new Context;
pCon->SetState(pSt_A); //一定要先设置一个状态再调用操作函数Operation
pCon->Operation(); //实际上是 ConcreateState_A的Handle函数在进行,且它把Context状态变为B
pCon->Operation(); //实际上是 ConcreateState_A的Handle函数在进行,且它把Context状态变为A
pCon->Operation();
pCon->Operation();
return 0;
}
State模式问题主要是逻辑分散化,状态逻辑分布到了很多的State的子类中,很难看到整个的状态逻辑图,这也带来了代码的维护问题。
4,Observer (观测者模式)
对同一组数据进行统计分析时候,我们希望能够提供多种形式的表示(例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有的统计的显示都能够同时改变。Observer模式就是解决了这一个问题。也就是说,观测者的任务是:当一多个事物依赖于一个事物时,这个事物变化的时候,那多个事物能随着变化.
上图中,attach,Detach用来注册/注销Observer对象到Subject对象中, 注册之后,如果Subject调用了SetState则说明Subject改变了,这时,它应该发送Notity消息, 则各个Observer对象都要进行相应的改变.
class Observer
{
public:
virtual void Update()=0;
};
class Subject
{
public:
virtual string GetState()=0;
virtual void SetState(string sta)=0;
virtual void Attach(Observer*pOb){ list_Ob.push_back(pOb); }
virtual void Detach(Observer*pOb){ list_Ob.remove(pOb); }
virtual void Notify() //当Subject发出改变通知后,各个Observer自动更新
{
list
for (;it_Ob!=list_Ob.end();++it_Ob)(*it_Ob)->Update();//各个Observer自动更新
}
private:
list
};
class ConcreateSubject:public Subject
{
public: //注意,其他三个方法都没有重定义了.
string GetState(){ return _state; }
void SetState(string sta){ _state=sta;/* Notify();*/ }//如果Notify()不注释掉
private: //就能做到真正的Subject一变,
string _state; //Observer立即跟着变,只是出于这样一种考虑:有时
}; //虽然Subject变化了,但却并不希望Observer改变
class ConcreateObserver_A:public Observer
{
public:
ConcreateObserver_A(Subject*pSub){ _pSub=pSub; }
void Update(){ cout<<"Now the Subject state is: "<<_pSub->GetState()
<<" and I--ConcreateObserver_A-- am changing my state/n"; } //观测者更新
private:
Subject*_pSub;
};
class ConcreateObserver_B:public Observer
{
public:
ConcreateObserver_B(Subject*pSub){ _pSub=pSub; }
void Update(){ cout<<"Now the Subject state is: "<<_pSub->GetState()
<<" and I--ConcreateObserver_B-- am changing my state/n"; } //观测者更新
private:
Subject*_pSub;
};
int main()
{
Subject*pSub=new ConcreateSubject;
Observer*pOb_A=new ConcreateObserver_A(pSub);//由于这里用的是指针参数,所以尽管在
Observer*pOb_B=new ConcreateObserver_B(pSub);//构造ConcreateObserver之前没有pSub->SetState
//而在构造之后才SetState,结果也是一样的.
pSub->Attach(pOb_A);//注册
pSub->Attach(pOb_B);
pSub->SetState("old");//状态设为old
pSub->Notify(); //发出改变消息(状态是old了),两个Observer都要改变
pSub->SetState("new");//Subject的状态由old改变为new
pSub->Notify(); //再次发出状态变化消息
pSub->Detach(pOb_A); //注销
pSub->Detach(pOb_B);
return 0;
}
5,Memento(备忘录)
如操作系统的”系统还原”,可以通过Memento模式实现.另外如Undo,Redo也可以用Memento.这种模式常常需要大量的物理空间.
上图中,以VC编程为例,调用Caretaker::SetMemento就设置了一个旧的状态,调用UnDo时,就相当于按下了VC上那个弯键.将state换成一个复杂的结构体,记录下很多信息,就能实现VC的UNDO功能!
typedef string state;
class Memento //备忘录
{
public:
Memento(state sta){ mem_state=sta; }
state GetState(){ return mem_state; }
private:
state mem_state; //备忘录保存的状态对象
};
class Originator //老状态
{
public:
//必须先SetState再CreateMemento
void SetState(state sta){ ori_state=sta; }
state GetState(){ return ori_state; } //用于测试,可得知当前状态
//生成一个备忘录对象,并将本身的状态对象传递/保存到备忘录中去.
Memento* CreateMemento(){ pOriMem= new Memento(ori_state); return pOriMem; }
private:
state ori_state; //软件主体(如VC)的状态
Memento* pOriMem;
};
class Caretaker // 照看者,调用者
{
public:
Caretaker(){ pCarMem=NULL; }
void SetMemento(Memento* pMem){ pCarMem=pMem; }//这里的pMem通过Originator的CreateMemento
//函数来实例化.
Memento*GetMemento(){ return pCarMem; }
state GetOldState(){ return GetMemento()->GetState(); }
void UnDo(Originator * pOri ){ pOri ->SetState(GetOldState()); }
private:
Memento* pCarMem;
};
int main()
{
state Old="ON",New="OFF";
Originator* pOri = new Originator;
pOri->SetState(Old); //当前主体状态为Old
cout<<"Current state of Originator is : "<
Caretaker* pCar = new Caretaker;
pCar->SetMemento(pOri->CreateMemento());//一旦调用SetMemento就好比VC中按下"Undo"按钮
//时,要先找到旧的状态,如果要保存多步状态,则这里可能不是Old作参数
pOri->SetState(New); //主体已经进入一个新的状态New
cout<<"Current state of Originator is : "<
cout<<"The old state of Memento is :"<
pCar->SetMemento(pOri->CreateMemento());//由于Originator只有一个State值,
//故本程序只能保存一步状态,可以扩展到多步.
pCar->UnDo(pOri);//**********这才是目标!!*************
cout<<"Current state of Originator is : "<
cout<<"The new state of Memento is :"<
return 0;
}
6,Mediator(中介模式)
大型系统中的许多对象间的通信常常很复杂, 而如果使用Mediator模式, 专门建立一个类来维护对象间的通信,则可以使得各个对象间不必相互声明就能够通信,会大大地简化系统.
Mediator模式中,每个Colleague维护一个Mediator,当要进行交互,例如图中ConcreteColleagueA和ConcreteColleagueB之间的交互就可以通过ConcreteMediator提供的DoActionFromAtoB来处理,ConcreteColleagueA和ConcreteColleagueB不必维护对各自的引用,甚至它们也不知道各个的存在。Mediator通过这种方式将多对多的通信简化为了一(Mediator)对多(Colleague)的通信。
class Mediator;
class Colleage
{
public:
virtual void Communicate(Colleage*pC)=0;
virtual void SayHello(string hello)=0; //奇怪,VC7下这里不用纯虚函数会报错,怪事.
protected:
Colleage(Mediator*pMedia){ _pMedia=pMedia; }
Mediator*_pMedia;
};
class ConcreateColleage_A:public Colleage
{
public:
void Communicate(Colleage*pB); //尚未定义
void SayHello(string hello){ cout<<"CC_A said: "<
ConcreateColleage_A(Mediator*pMedia):Colleage(pMedia){ }
};
class ConcreateColleage_B:public Colleage
{
public:
void Communicate(Colleage*pA); //尚未定义
void SayHello(string hello){ cout<<"CC_B said: "<
ConcreateColleage_B(Mediator*pMedia):Colleage(pMedia){ }
};
class Mediator
{
public:
virtual void DoActionA_2_B()=0;
virtual void DoActionB_2_A()=0;
};
class ConcreateMediator:public Mediator
{
public:
void IntroColleage(Colleage*pColA,Colleage*pColB) { pCol_A=pColA; pCol_B=pColB; }
void DoActionA_2_B(){ pCol_A->SayHello("This is A/n"); }
void DoActionB_2_A(){ pCol_B->SayHello("This is B/n"); }
private:
Colleage*pCol_A;
Colleage*pCol_B;
};
//下面的函数中,参数pB的意义在于:当要通信的对象是pB时,实际调用的正好是DoActionA_2_B.
//而是pA时,调用的正好是DoActionB_2_A,如果还有其实的对象,则可照样扩展.
void ConcreateColleage_A::Communicate(Colleage*pB){ _pMedia->DoActionA_2_B(); }
void ConcreateColleage_B::Communicate(Colleage*pA){ _pMedia->DoActionB_2_A(); }
int main()
{
ConcreateMediator*pM = new ConcreateMediator;
Colleage*pA = new ConcreateColleage_A(pM);
Colleage*pB = new ConcreateColleage_B(pM);
pM->IntroColleage(pA,pB);
pA->Communicate(pB); //ConcreateColleage_A与ConcreateColleage_B通信
pB->Communicate(pA); //ConcreateColleage_B与ConcreateColleage_A通信
return 0;
}
7, Command(命令)
Command模式通过将请求封装到一个对象(Command)中,并将请求的接受者存放到具体的ConcreteCommand类中(Receiver)中,从而实现调用操作的对象和操作的具体实现者之间的解耦。
class Reciever //命令接收者,其操作为Action
{
public:
void Action(){ cout<<"I am the reciever, I got the command/n"; }
};
class Command //该类有一个Reciever*成员,可被继承,它有一个接口Excute,实际将调用Reciever::Action
{
public:
virtual void Excute()=0;
virtual void GetReciever(Reciever*pRecv)=0;
protected:
Reciever*pRecv;
};
class ConcreateCommand:public Command
{
public:
void GetReciever(Reciever*pRecv){ this->pRecv=pRecv; } //找到命令接收者.
void Excute(){ pRecv->Action(); }//Command接口Excute,实际将调用Reciever::Action
};
class Invoker //命令激活器
{
public:
void SetCommand(Command*pCmd){ this->pCmd=pCmd; }//设置命令
void Invoke(){ pCmd->Excute(); } //激活!执行命令!
private:
Command*pCmd;
};
int main()
{
Reciever*pRecv=new Reciever;
Command*pCmd=new ConcreateCommand;
pCmd->GetReciever(pRecv);
Invoker*pIk=new Invoker;
pIk->SetCommand(pCmd);
pIk->Invoke();
return 0;
}
8,Vistor(访问者)
在面向对象系统的开发和设计过程,经常会遇到一种情况就是需求变更,因此不得不去修改已有的设计,最常见就是解决方案就是给已经设计、实现好的类添加新的方法去实现客户新的需求,这样就陷入了设计变更的梦魇:不停地打补丁,其带来的后果就是设计根本就不可能封闭、编译永远都是整个系统代码。
Visitor模式则提供了一种解决方案:将更新(变更)封装到一个类中(访问操作),并由待更改类提供一个接收接口,则可达到要求的效果。
上图中,vistor要对element做的处理可以vistconelement_A/B方法中进行.
class Element;
class ConElement_A;
class ConElement_B;
class Vistor
{
public:
virtual void VistConElement_A(ConElement_A*pA)=0; //虽然本示例中这个指针参数没起到作用
virtual void VistConElement_B(ConElement_B*pB)=0; //但实际用于设计时,肯定会有用的.
};
class ConVistor_A:public Vistor
{
public:
void VistConElement_A(ConElement_A*pA){ cout<<"ConVistor_A will vist ConElement_A/n"; }
void VistConElement_B(ConElement_B*pB){ cout<<"ConVistor_A will vist ConElement_B/n"; }
};
class ConVistor_B:public Vistor
{
public:
void VistConElement_A(ConElement_A*pA){ cout<<"ConVistor_B will vist ConElement_A/n"; }
void VistConElement_B(ConElement_B*pB){ cout<<"ConVistor_B will vist ConElement_B/n"; }
};
class Element
{
public:
virtual void Accept(Vistor*pV)=0;
};
class ConElement_A:public Element
{
public:
void Accept(Vistor*pV){ pV->VistConElement_A(this); }
void Operation_B(){ }
};
class ConElement_B:public Element
{
public:
void Accept(Vistor*pV){ pV->VistConElement_B(this); }
void Operation_A(){ }
};
class Manger
{
public:
void AttachElement(Element*pE){ list_Element.push_back(pE); }
void DetachElement(Element*pE){ list_Element.remove(pE); }
void AcceptVistor(Vistor*pV) //执行者
{
list_Vistor.push_back(pV);
list
for (;it_Element!=list_Element.end();++it_Element)(*it_Element)->Accept(pV);
}
private:
list
list
};
/*
通过管理器Manger,Element在管理器中注册,一旦调用Manger::AcceptVistor(ConVistor_X)
则能够被Element对象Accept的ConVistor_X的操作就会被执行.
*/
int main()
{
Manger*pManger=new Manger;
Element*pEA=new ConElement_A;
Element*pEB=new ConElement_B;
pManger->AttachElement(pEA); //注册
pManger->AttachElement(pEB);
Vistor*pVA=new ConVistor_A;
Vistor*pVB=new ConVistor_B;
pManger->AcceptVistor(pVA);//执行,实际上,pVA的VistConElement_A和VistConElement_A都将执行
pManger->AcceptVistor(pVB);
pManger->DetachElement(pEA);//注销
pManger->DetachElement(pEB);
return 0;
}
9, Chain of Responsibility(职责链)
在MFC中,消息会沿着固定的路径被传递,直到路径上某个对象将消息处理掉,如果半路上没被处理,则会被终极的App对象处理掉.
职责链模式就能够维护一条这样的”路径”,它的做法是将可能会处理某些(或某个)请求的对象链接成一条链,然后把请求放到这条链上来传递,直到请求被处理.
详看注释.
class Handle
{
public:
void SetHandle(Handle*pHan){ _pHan=pHan; } //这是每个对象都要使用的方法,用来形成对象链
//没有后续对象时,_pHan=NULL
Handle*GetHandle(){ return _pHan; } //获取后续对象
virtual void ProcessRequest(int RequestID)=0;
protected:
Handle*_pHan; //这是链中指针,指向下一个对象,注意其保护类型,可在派生时使用.
};
class ConCreateHandle_A:public Handle
{
public:
void ProcessRequest(int RequestID) //每个ConCreateHandle_A对不同的ID的请求做不同的处理
{ //在处理范围内
if(RequestID<0)cout<<"I can process the Request which ID is: "<
else if(GetHandle())//不在处理范围,但本对象还有后续对象
{
cout<<"My subsequencer will process the Request which ID is: "<
GetHandle()->ProcessRequest(RequestID);
}//不在处理范围,而且本对象没有后续对象了.
else cout<<"One body can process the Request which ID is: "<
}
};
class ConCreateHandle_B:public Handle
{
public:
void ProcessRequest(int RequestID)
{//上面只能处理ID小于0的请求,这里能处理ID小于100的.
if(RequestID<100)cout<<"I can process the Request which ID is: "<
else if(GetHandle())
{
cout<<"My subsequencer will process the Request which ID is: "<
GetHandle()->ProcessRequest(RequestID);
}
else cout<<"One body can process the Request which ID is: "<
}
};
int main()
{
Handle*pHA=new ConCreateHandle_A;
Handle*pHB=new ConCreateHandle_B;
pHA->SetHandle(pHB);//本例中SetHandle是每个对象必须调用的.
pHB->SetHandle(NULL);
int RequestID=200;
pHA->ProcessRequest(RequestID); //让一个ID为200的请求在链上传递
return 0;
}
10,Iterator(迭代器)
这个模式可以参考STL中迭代器的意义来理解,STL中的迭代器通过一个类似指针的模板类实现对list,string等聚合对象的遍历.
Iterator模式也正是用来解决对一个聚合对象的遍历问题,将对聚合的遍历封装到一个类中进行,这样就避免了暴露这个聚合对象的内部表示的可能。
代码:
class Iterator;
class List_It;
class Vector_It;
class Container
{
public:
// Container(){ ++size; pNextCon=NULL; }//用一个表态变量size来标记容器大小,构造一次自增一回
virtual Iterator*CreaeteIterator()=0;
void Add(Container*pNextCon){ this->pNextCon=pNextCon; } //往容器中聚合更多对象
Container*GetNextContainer(){ return pNextCon; } //下一个结点
/*其他方法略*/
protected:
Container*pNextCon;
};
class List:public Container //容器List
{
public:
List(){ ++size; }
Iterator*CreaeteIterator();
int GetSize(){ return size; } //得到窗口大小
private:
static int size;
};
int List::size=0;
class Vector:public Container //容器Vector
{
public:
Vector(){ ++size; }
Iterator*CreaeteIterator();
int GetSize(){ return size; } //得到窗口大小
private:
static int size;
};
int Vector::size=0;
class Iterator //迭代器
{
public:
virtual Container* First()=0;//第一个位置
virtual Container* Next()=0; //下一个位置
virtual int GetSize()=0; //容器大小
};
class List_It:public Iterator
{
public:
List_It(List*pList){ this->pList=pList; } //以对应的容器指针为参数构造迭代器
List*GetList(){ return pList; }
Container*First(){ return pList; } //这里粗制滥造了,主要用于模拟
Container*Next(){ return GetList()->GetNextContainer(); }
int GetSize(){ return pList->GetSize(); }
private: //迭代器必须有一个与之对应的容器指针
List*pList;
};
class Vector_It:public Iterator
{
public:
Vector_It(Vector*pVector){ this->pVector=pVector; }
Vector* GetVector() { return pVector; }
Container*First(){ return pVector; }
Container*Next(){ return GetVector()->GetNextContainer(); }
int GetSize(){ return pVector->GetSize(); }
private:
Vector*pVector;
};
Iterator* List::CreaeteIterator(){ return new List_It(this); } //List构造自己的迭代器
Iterator* Vector::CreaeteIterator(){ return new Vector_It(this); }//Vector构造自己的迭代器
int main()
{
List*pLA=new List;
List*pLB=new List;
List*pLC=new List;
pLA->Add(pLB);//组成一个有三个List对象的链
pLB->Add(pLC);
pLC->Add(NULL);
Iterator*pLIt=pLA->CreaeteIterator();//构造一个List_It 迭代器
int list_size=pLIt->GetSize(); //用迭代器来获取容器的大小
cout<<"The size of the Chain of List-Objs is: "<
Vector*pVA=new Vector;
Vector*pVB=new Vector;
Vector*pVC=new Vector;
Vector*pVD=new Vector;
pVA->Add(pVB);
pVB->Add(pVC);
pVC->Add(pVD);
pVD->Add(NULL);
Iterator*pVIt=pVA->CreaeteIterator();
int vector_size=pVIt->GetSize();
cout<<"The size of the Chain of Vector-Objs is: "<
return 0;
}
Interpreter模式能够为一门语言定义一个解释器,通过这个解释器可能解释该门语言的句子.
如果某种类型的问题发生的频率非常高,就值得为该类型问题的各个实例定义一个句子,并实现该句子的一个解释器,从此以后,解决该类型的问题就不会很费事了.
class ExpressionContext
{
public:
ExpressionContext(string context){ this->context=context; }
string GetContext(){ return context; }
private:
string context;
};
class Expression
{
public://解释语句,不同的语句由不同的派生类解释
virtual void Interpre(ExpressionContext*pContext)=0;
};
class TerminalExpression:public Expression
{
public:
void Interpre(ExpressionContext*pContext) //一种解释
{ cout<<"TermianlExpression--"<
};
class NonterminalExpression:public Expression
{
public:
void Interpre(ExpressionContext*pContext)//又一种解释
{ cout<<"NonermianlExpression--"<
};
int main()
{
ExpressionContext*pContext1=new ExpressionContext("hello world");
ExpressionContext*pContext2=new ExpressionContext("HELLO WORLD");
Expression*pExTer=new TerminalExpression;
pExTer->Interpre(pContext1); //小写的解释
Expression*pExNonter=new NonterminalExpression;
pExNonter->Interpre(pContext2);//大写的解释
return 0;
}