行为型模式
包括:迭代器模式(Iterator)、中介者模式(Mediator)、解释器模式(Interpreter)、状态模式(State)、责任链模式(Chain of Responsibility)、访问者模式(Visitor)。
中介者模式
定义:用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互。
类图:
- 抽象中介者:定义好同事类对象到中介者对象的接口,用于各个同事类之间的通信。一般包括一个或几个抽象的事件方法,并由子类去实现。
- 中介者实现类:从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。
- 同事类:如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。
本文就以租房为例子,如果没有房屋中介,那么房客要自己找房东,而房东也要自己找房客,非常不方便。有了房屋中介机构就方便了。
|
|
适用场景:
一般来说,只有对于那种同事类之间是网状结构的关系,才会考虑使用中介者模式。可以将网状结构变为星状结构,使同事类之间的关系变的清晰一些。
责任连模式
定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
类图:
- 抽象处理类:抽象处理类中主要包含一个指向下一处理类的成员变量nextHandler和一个处理请求的方法handRequest,handRequest方法的主要主要思想是,如果满足处理的条件,则有本处理类来进行处理,否则由nextHandler来处理。
- 具体处理类:具体处理类主要是对具体的处理逻辑和处理的适用条件进行实现。
其思想很简单,考虑员工要求加薪。公司的管理者一共有三级,总经理、总监、经理,如果一个员工要求加薪,应该向主管的经理申请,如果加薪的数量在经理的职权内,那么经理可以直接批准,否则将申请上交给总监。
|
|
状态模式
状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。它有两种使用情况:(1)一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。(2)一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
以战争为例,假设一场战争需经历四个阶段:前期、中期、后期、结束。
|
|
访问者模式
定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
类图:
- 抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法中的参数定义哪些对象是可以被访问的。
- 访问者:实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。
- 抽象元素类:接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。抽象元素一般有两类方法,一部分是本身的业务逻辑,另外就是允许接收哪类访问者来访问。
- 元素类:实现抽象元素类所声明的accept方法,通常都是visitor.visit(this),基本上已经形成一种定式了。
- 结构对象:一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中一般很少抽象出这个角色。123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136using namespace std;class ConcreteElementA;class ConcreteElementB;class Visitor{public:virtual void VisitConcreteElementA(ConcreteElementA *pElementA) = 0;virtual void VisitConcreteElementB(ConcreteElementB *pElementB) = 0;};class ConcreteVisitor1 : public Visitor{public:void VisitConcreteElementA(ConcreteElementA *pElementA);void VisitConcreteElementB(ConcreteElementB *pElementB);};void ConcreteVisitor1::VisitConcreteElementA(ConcreteElementA *pElementA){// 现在根据传进来的pElementA,可以对ConcreteElementA中的element进行操作}void ConcreteVisitor1::VisitConcreteElementB(ConcreteElementB *pElementB){// 现在根据传进来的pElementB,可以对ConcreteElementB中的element进行操作}class ConcreteVisitor2 : public Visitor{public:void VisitConcreteElementA(ConcreteElementA *pElementA);void VisitConcreteElementB(ConcreteElementB *pElementB);};void ConcreteVisitor2::VisitConcreteElementA(ConcreteElementA *pElementA){// ...}void ConcreteVisitor2::VisitConcreteElementB(ConcreteElementB *pElementB){// ...}// Element objectclass Element{public:virtual void Accept(Visitor *pVisitor) = 0;};class ConcreteElementA : public Element{public:void Accept(Visitor *pVisitor);};void ConcreteElementA::Accept(Visitor *pVisitor){pVisitor->VisitConcreteElementA(this);}class ConcreteElementB : public Element{public:void Accept(Visitor *pVisitor);};void ConcreteElementB::Accept(Visitor *pVisitor){pVisitor->VisitConcreteElementB(this);}// ObjectStructure类,能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素class ObjectStructure{public:void Attach(Element *pElement);void Detach(Element *pElement);void Accept(Visitor *pVisitor);private:vector<Element *> elements;};void ObjectStructure::Attach(Element *pElement){elements.push_back(pElement);}void ObjectStructure::Detach(Element *pElement){vector<Element *>::iterator it = find(elements.begin(), elements.end(), pElement);if (it != elements.end()){elements.erase(it);}}void ObjectStructure::Accept(Visitor *pVisitor){// 为每一个element设置visitor,进行对应的操作for (vector<Element *>::const_iterator it = elements.begin(); it != elements.end(); ++it){(*it)->Accept(pVisitor);}}int main(){ObjectStructure *pObject = new ObjectStructure;ConcreteElementA *pElementA = new ConcreteElementA;ConcreteElementB *pElementB = new ConcreteElementB;pObject->Attach(pElementA);pObject->Attach(pElementB);ConcreteVisitor1 *pVisitor1 = new ConcreteVisitor1;ConcreteVisitor2 *pVisitor2 = new ConcreteVisitor2;pObject->Accept(pVisitor1);pObject->Accept(pVisitor2);if (pVisitor2) delete pVisitor2;if (pVisitor1) delete pVisitor1;if (pElementB) delete pElementB;if (pElementA) delete pElementA;if (pObject) delete pObject;return 0;}
访问者模式的适用场景:假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。
迭代器模式
定义:提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。
类图:
- 抽象容器:一般是一个接口,提供一个iterator()方法
- 具体容器:就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。
- 抽象迭代器:定义遍历元素所需要的方法,一般来说会有这么三个方法:取得第一个元素的方法first(),取得下一个元素的方法next(),判断是否遍历结束的方法isDone()(或者叫hasNext()),移出当前对象的方法remove(),
- 迭代器实现:实现迭代器接口中定义的方法,完成集合的迭代。
|
|
解释器模式
定义:给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。
类图:
- 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作。具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器NonterminalExpression完成。
- 终结符表达式:实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。终结符一半是文法中的运算单元,比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。
- 非终结符表达式:文法中的每条规则对应于一个非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,+就是非终结符,解析+的解释器就是一个非终结符表达式。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。
- 环境角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。