行为型模式设计到算法和对象间的职责分配,不仅描述对象或类的模式,还描述它们之间的通信方式,刻划了运行时难以跟踪的复杂的控制流,它们将你的注意力从控制流转移到对象间的关系上来。行为型类模式采用继承机制在类间分派行为,例如Template Method 和Interpreter;行为对象模式使用对象复合而不是继承。一些行为对象模式描述了一组相互对等的对象如何相互协作以完成其中任何一个对象都单独无法完成的任务,如Mediator、Chain of Responsibility、Strategy;其它的行为对象模式常将行为封装封装在一个对象中,并将请求指派给它。
常见行为型模式有11种:CCIIMM(Chain of Responsibility职责链、Command命令、Interpreter解释器、Iterator迭代、Mediator中介者、Memento备忘录),OSSTV(Observer观察者、State状态、Strategy策略、Template Method模版方法、Visitor访问者)。
-
职责链模式(Chain of Responsibility):将对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。职责链可简化对象的相互连接,它们仅需保持一个指向后继者的引用,而不需要保持所有候选者的引用,链中对象不用知道链的结构,接受者和发送者都没有对方的明确信息。可以通过在运行时刻动态的增加或修改链来动态的改变处理一个请求的职责;不能保证请求一定被接受,一个请求也可能因链没有被正确配置而得不到处理。
参与者:
(1)Handler:定义一个实现请求的接口。
(2)ConcreteHandler:处理它负责的请求,可访问它的后继者;如果可处理请求就处理,否则将请求转发给它的后后继者。
(3)Client:向链上的具体处理者对象提交请求。
协作:当客户提交一个请求时,请求沿着链传递直至有一个ConcreteHandler对象负责处理它或者到链末。
-
命令模式(Command):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。别名动作(Action),事务(Transaction)。和很多设计模式一样,命令模式在你的请求和处理之间加上了一个中间人的角色,来达到分离耦合的目的。
参与者:
(1):命令角色(Command):声明执行操作的接口。
(2)具体命令角色(ConcreteCommand):讲一个接受者对象绑定一个动作;调用接收者相应的操作,以实现命令角色声明的执行操作的接口。
(3)客户角色(Client): 创建一个具体命令对象(并可以设定它的接收者)。
(4)请求者角色(Invoker):调用命令对象执行请求。
(5)接收者角色(Receiver):知道如何实施与执行一个请求相关的操作。任何类都可能做一个接收者。
协作:Client创建一个具体的ConcreteCommand对象并指定它的Receiver对象;某Invoker对象存储该ConcreteCommand对象,通过调用Command对象的Execute操作来提交一个请求,若该命令是可撤销的,ConcreteCommand就在执行Execute操作之前存储当前状态以用于取消该命令;ConcreteCommand对象调用它的Receiver的一些操作以执行该请求。
总结:命令模式将调用操作的请求对象和知道如何实现操作的接受对象解耦;具体命令角色可被不同的请求者角色重用,它可将多个命令装配成一个复合命令,增加新的具体命令角色无需改变已有的类。Gof总结命令模式适用以下情况:(1)需要抽象出待执行的动作,然后以参数的形式提供出来(类似于过程设计中的回调机制),命令模式正是回调机制的一个面向对象的替代品。(2)在不同的时刻指定、排列和执行请求。一个命令对象可以有与初始请求无关的生存期。(3)需要支持取消操作(4)支持修改日志功能,支持事务操作。从面向对象角度看命令模式是不完美的,命令角色仅仅包含一个方法,是将函数层的角色提升到了类的层面,但命令模式很成功的解决了很多问题,遍布在Struts中。
-
解释器模式(Interpreter):定义语言(使用规定格式和语法的代码)的文法,并且建立一个解释器来解释该语言中的句子。它属于类行为模式。解释器模式提供一种简单方法来执行语法且容易修改和扩展。一般系统中很多类使用相似的语法,可以使用一个解释器来代替每一个规则实现一个解释器。在解释器中不同规则是由不同类实现的,从而使添加一个新的语法规则简单化,但对于复杂语法难以维护。
4.迭代器模式(Iterator):提供一种方法顺序访问一个集合中各个元素,而又不暴露该对象的内部表示。别名:游标(Cursor)。
5.中介者模式(Mediator):用一个中介对象封装一系列的对象交互。中介者使各对象间不需要显式的相互引用,从而使其松散耦合,而起可以独立的改变它们之间的交互。
参与者:
(1)Mediator(中介者):定义一个接口用于和同事对象间通信。
(2)ConcreteMediator(具体中介者):协调各同事对象对象实现协作行为;了解并维护它的各个同事。
(3)Colleague(同事角色):每一个同事角色都知道它的中介者对象,在需要与其它同事通信时,与它的中介者通信。
协作:同事向一个中介者发送和接收请求。中介者在各同事间适当的转发请求以实现协作行为。
总结:广泛应用的MVC也算是中介者模式在框架设计中的一个应用(控制层是位于表现层和模型层之间的中介者)。中介者模式在结构上和观察者模式、命令模式相似,而应用目的与外观模式相似。在结构上,中介者模式与观察者模式和命令模式都添加了中介对象——只是中介模式去掉了后两者行为上的方向。但观察者模式中的观察者、命令模式中的命令都是被客户所知的,具体哪个观察者、应用都是由客户来指定的,而大多中介者角色对客户是透明的,造成这种区别的原因是它们要达到的目的不同。从目的上看,命令模式与外观模式相似;但外观模式是介于客户程序与子系统之间的,而中介者模式是介于子系统与子系统之间的;前者将复杂的逻辑提取出一个统一的接口,简化客户对逻辑的使用,而后者的加入并没有改变客户原有的使用习惯,它是隐藏在原有逻辑后面的,使得代码逻辑更加清晰可用。中介者模式最大的好处是将同事角色解耦,简化原有系统的通信协议——将原有的多对多变为一对多,提高了代码的可复用性。在使用中介者模式时要注意控制中介者角色的大小。
6.备忘录模式(Memento):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以后可将该对象恢复到原先保存的状态。别名:Token。
参与者:
(1)Memento(备忘录角色):存储备忘发起角色的内部状态,备忘发起角色根据需要决定备忘录角色存储自己哪些内部状态。为了防止备忘发起角色以往的对象访问备忘录,管理者只能看到备忘录的窄接口——它只能把备忘录传递给其它对象,原备忘发起角色可以看到一个宽接口,允许它访问返回到先前状态所需的所有数据。
(2)Originator(原发器,备忘发起角色):创建一个备忘录,用于记录当前时刻它的内部状态,在需要时使用备忘录恢复内部状态。
(3)Caretaker(管理器,备忘录管理者角色):负责管理备忘录,不能对备忘录的内容进行操作或检查。
协作:管理器向原发器请求一个备忘录,保留一段时间后将其返回给原发器。备忘录是被动的,只有创建备忘录的原发器会对它的状态进行赋值和检索。
7.观察者模式(Observer):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并自动更新。别名:Dependents(依赖),发布-订阅(Publish-subscribe)。
参与者:
(1)Subject(抽象目标角色):提供注册和删除观察者对象的接口,知道它的观察者。可以有任意多个观察者观察同一个目标。
(2)Observer(观察者角色):为那些在目标发生改变时需要更新的对象定义一个更新接口。
(3)ConcreteSubject(具体目标):将有关状态存入ConcreteObserver对象,当它的状态发生改变时,向它的各个观察者发出通知。
(4)ConcreteObserver(具体观察者):维护一个指向ConcreteSubject对象的引用,存储有关状态,这些状态应与目标状态保持一致,实现Observer的更新接口,以使自己状态与目标状态保持一致。
协作:当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知各个观察者。在得到一个具体目标的改变通知后,ConcreteObserver可向目标对象查询信息,从而使它的状态与目标对象状态保持一致。
8状态模式(State):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。别名:状态对象。
参与者:
(1)Context(环境):维护一个ConcreteState实例,这个实例定义当前状态。
(2)State(状态):定义一个接口以封装与Context的一个特定状态相关的行为。
(3)ConcreteState(具体状态):实现一个与Context的一个状态相关的行为。
协作:Context将与状态相关的请求委托给当前的ConcreteState对象处理,也可将自身作为一个参数传递传递给以处理该请求的状态对象,从而使状态对象在必要时可访问Context。Context是客户使用的主要接口,客户可用状态对象来配置一个Context,一旦Context配置完毕,它的客户不再需要直接与状态对象打交道。Context和ConcreteState子类都可决定哪个状态时另外哪一个状态的后继者,以及在何种条件下进行状态转换。
9.策略模式(Strategy):定义一系列算法,把它们一个个封装起来,并且使它们可相互替换,本模式使得算法可独立于使用它的客户而变化。别名:政策(policy)。
参与者:(1)Strategy(策略):定义所有支持算法的公共接口。Context使用这个接口来调用某个Concretestrategy定义的算法。
(2)ConcreteStrategy(具体策略):以Strategy为接口实现某具体算法。
(3)Context(上下文):维护一个Strategy对象的引用,用一个ConcreteStrategy来配置,可定义一个接口来让Strategy访问它的书籍。
协作:Strategy和Context相互作用以实现选定的算法。当算法被调用时,Context可将该算法所需要的所有数据都传递给Strategy,或者Context可将自身作为一个参数传递给Strategy操作,从而使Strategy在需要时可以回调Context。Context将它的客户请求转发给它的Strategy,客户通常创建并传递一个ConcreteStrategy对象给该Context;这样客户仅与Context交互。通常有一系列ConcreteStrategy类可供客户从中选择。
State对比Strategy:Strategy模式和State模式在结构上非常相似,但在概念上它们间的目的差异非常大。区分这两个模式的关键是看行为是由状态驱动还是由一组算法驱动,通常State模式的状态时在对象内部的,Strategy模式的策略可在对象外部,即这两个模式的区分就在于使用的目的不同——策略模式用来处理算法变化,而状态模式则是处理状态变化。算法是否变化完全是由客户程序决定的,而且往往一次只能选择一种算法,不存在算法中途变化的情况。而状态模式如定义中所言,在它的生命周期中存在着状态的转变和行为的更改,而且状态变化是一个线性的整体;对客户而言,这种状态的变化往往是透明的。
10.模版方法模式(Template Method):定义一个操作中算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法的某些特定的步骤。模版方法是一种基本代码复用技术,在类库中尤为重要,它们提取了类库中的公共行为。算法的结构可理解为根据需求设计出来的业务流程,特定的步骤就是指那些可能在内容上存在变数的环节。
参与者:(1)AbstractClass(抽象类):定义一个模版方法,定义一个算法的骨架;定义抽象的原语操作,具体的子类将重定义它们以实现算法的各个步骤。该模版方法不仅调用原语操作,也调用定义在AbstractClass或其它对象中的操作。
(2)ConcreteClass(具体类)实现原语操作以完成算法中子类相关的特定步骤。
协作:ConcreteClass靠AbstractClass来实现算法中不变的步骤。
实例:Junit。
适用情况:(1):一次性实现算法的不变的部分,并将可变的行为留给子类来实现。
(2):各子类中公共的行为应该被提取出来并集中到一个公共父类中以避免代码重复。
(3):控制子类扩展。
11.访问者模式(Visitor):表示以作用于对象结构中各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
参与者:(1)Visitor(访问者):为该对象结构中每一个ConcreteElement声明一个Visit操作,该操作的名称和特征标志了发送Visit请求给该标识者的那个类,使访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
(2)ConcreteVisitor(具体访问者):实现每个Visitor声明的操作。每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。ConcreteVisitor为该算法提供了上下文并存储它的局部状态,这一状态常常在遍历该结构的过程中累积结果。
(3)Element(元素):定义一个Accept操作,它以一个访问者为参数。
(4)ConcreteElement(具体元素):实现Accept操作,该操作以一个访问者为参数。
(5)ObjectStructure(对象结构):可以是一个复合,提供一个高层接口以允许访问者访问它的元素,能枚举它的元素。
协作:一个使用Visitor模式的客户必须创建一个ConcreteVisitor对象,然后遍历该对象结构,并用该访问者访问每一个元素。当一个元素被访问时它调用对应它的类的Visitor操作,如有必要该元素将自身作为操作的一个参数以便该访问者访问它的状态。
总结:行为模式涉及到算法和对象职责间的分配,行为类模式采用继承机制在类间分派行为,Template Method和Interpreter是类行为模式。行为对象模式使用对象复合而不是继承,一些行为对象模式描述了一组相互对等的对象如何相互协作以完成其中任何一个对象都单独无法完成的任务,如Mediator在对象间引入一个mediator对象提供了松耦合所需的间接性;Chain of Responsibility提供了更松的耦合,它通过一条候选对象链隐式的向一个对象发松请求,可以运行时刻决定哪些候选者参与到链中;Observer定义并保持了对象间的依赖关系;其它的行为对象模式常将行为封装封装在一个对象中,并将请求指派给它,Strategy模式将算法封装在对象中,这样可以方面的改变和指定一个对象所使用的算法;Command模式将请求封装在对象中,这样它就可以作为参数来传递,已可以存储在历史列表中或以其它方式使用;State模式封装一个对象的状态,使得当这个对象的状态对象变化时,该对象可改变它的行为;Visitor模式封装分布于多个类之间的行为;而Iterator模式则抽象了访问和遍历一个集合中对象的方式。