《设计模式可复用面向对象软件的基础行为模式》由会员分享,可在线阅读,更多相关《设计模式可复用面向对象软件的基础行为模式(58页珍藏版)》请在金锄头文库上搜索。
1、第5章行为模式行为模式涉及到算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述它 们之间的通信模式。这些模式刻划了在运行时难以跟踪的复杂的控制流。它们将你的注意力从 控制流转移到对象间的联系方式上来。行为类模式使用继承机制在类间分派行为。本章包括两个这样的模式。其中Te m p l a t e Me t h o d (5 . 1 0)较为简单和常用。模板方法是一个算法的抽象定义,它逐步地定义该算法,每 一步调用一个抽象操作或一个原语操作,子类定义抽象操作以具体实现该算法。另一种行为类模式是I n t e r p r e t e r (5.3)。它将一个文法表示为一个类层次,并实现一
2、个解释器作为这些类 的实例上的一个操作。行为对象模式使用对象复合而不是继承。一些行为对象模式描述了一组对等的对象怎样相 互协作以完成其中任一个对象都无法单独完成的任务。这里一个重要的问题是对等的对象如何 互相了解对方。对等对象可以保持显式的对对方的引用,但那会增加它们的耦合度。在极端情 况下,每一个对象都要了解所有其他的对象。M e d i a t o r (5.5)在对等对象间引入一个m ed i a t o r对象以防止这种情况的出现。m e d i a t o r提供了松耦合所需的间接性。Chain of Responsibility(5.1)提供更松的耦合。它让你通过一条候选对象链隐式
3、的向一个对象 发送请求。根据运行时刻情况任一候选者都可以响应相应的请求。候选者的数目是任意的,你可以在运行时刻决定哪些候选者参与到链中。O b s e r v e r ( 5.7 )模式定义并保持对象间的依赖关系。典型的O b s e r v er的例子是Smalltalk中的模型/视图/控制器,其中一旦模型的状态发生变化,模型的所有视图都会得到通其他的行为对象模式常将行为封装在一个对象中并将请求指派给它。模式将算法封装在对象中,这样可以方便地指定和改变一个对象所使用的算法。(5.2 )模式将请求封装在对象中,这样它就可作为参数来传递,也可以被存储在历史列表里,或者以其他方式使用。S t a
4、t e ( 5.8 )模式封装一个对象的状态,使得当这个对象的状态对象变化时,该对象可改变它的行为。Vi s i t o r ( 5 . 11 )封装分布于多个类之间的行为,而I t e r ato r ( 5.4 )那么抽象了访问和遍历一个集合中的对象的方式。5.1 CHAIN OF RESPONSIBILITY( 职责链)一对象行为型模式1. 意图使多个对象都有时机处理请求,从而防止请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。2. 动机考虑一个图形用户界面中的上下文有关的帮助机制。用户在界面的任一局部上点击就可以得到帮助信息,
5、所提供的帮助依赖于点击的是界面的哪一局部以及其上下文。例如,对话框中的按钮的帮助信息就可能和主窗口中类似的按钮不同。如果对那一局部界面没有特定的帮助信一比方说,整个对话框息,那么帮助系统应该显示一个关于当前上下文的较一般的帮助信息148 设计模式r离复用面向对象孰件的根底因此彳艮自然地,应根据普遍性 (g e n e r a l i t y )即从最特殊到最普遍的顺序来组织帮助信息。而且,很明显,在这些用户界面对象中会有一个对象来处理帮助请求;至于是哪一个对象那么取决于上下文以及可用的帮助具体到何种程度。这儿的问题是 提交帮助请求的对象(如按钮)并不明确知道谁是 最终提供帮助的对象。我们要有一
6、种方法将 提交帮助请求的对象与可能提供帮助信息的对象解耦(d e c o u p l e )。Chain ofR e s p o n s i b i l i t y模式告诉我们应该怎么做。这一模式的想法是,给多个对象处理一个请求的时机,从而解耦发送者和接受者。该请求 沿对象链传递直至其中一个对象处理它,如以下图所示。从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者。提交请求的对象并不明确地知道哪一个对象将会处理它一我们说该请求有一个隐式的接收者(implicit receiver)。假设用户在一个标有P r i n t 的按钮窗口组件上单击帮助,而该按钮包含在一
7、个Pr i n t D(见前面的对象框图)。下面的交互框图ia l og的实例中,该实例知道它所属的应用对象(diagram)说明了帮助请求怎样沿链传递在这个例子中,既不是 aPrintButton也不是 aPrintDialog 处理该请求;它一直被传递给n A p p l i c a t i o n , anApplication 处理它或忽略它。提交请求的客户不直接引用最终响应它 的对象。要沿链转发请求,并保证接收者为隐式的(i m p l i c i t ),每个在链上的对象都有一致的处理请求和访问链上后继者的接口。例如,帮助系统可定义一个带有相应的HandleHelp 操作的H e
8、l p H a n d l e r类。HelpHandler 可为所有候选对象类的父类,或者它可被定义为一个 混入(m i x i n )类。这样想处理帮助请求的类就可将HelpHandler 作为其一个父类,如下页上图所示。按钮、对话框,和应用类都使用HelpHandler操作来处理帮助请求。H e l p H a nd l e r 的* I-%!* -e-MiMW,v m n*MjiTwriw 詈 ktwa mqjuw*1 不 flifrlAcatlMMnu. whJMKiiJnandilw t* &r MBnMMV Itwt vdUvm.fc tUtbm-fdl A re-CT* rwf
9、-D-ttlrD -ETTIrCI-C-f: Ct-kMt: VJK1 tl.mait-ul 3T ru.m I=Lb At-* b -i . I *函. 目曲 n 9 h f-4 i M I i i叱:- =t 喉正 *一11一 土I *14 I l n-Vil-4 9 !* I V 4 I +f+ , . q断.I V T . 断 4 Ml1 * I -*v i fclrk m f-tj-nrmbkjk I irih- *-fc11-1-*-: C JBiMiBMKIM - OI- 1 f A % Iri-M- L AJW .* nb M Hrm IPVM - a |1t-BiW t -K
10、rfl.KMl!WM E tIM , I lLF IKmA匚&_专m rsm墓e, ILui1下载up jpfc lrirC-j3 iv4Z|u-c4kEk unt*i ma luzjJ (,zti c?bj2rt on ttwr du in whi ww n common intfrrfaicc? for HancjliriK mr可umig aruiHandleHelp操作缺省的是将请求转发给后继。子类可重定义这一操作以在适当的情况下提供帮 助;否那么它们可使用缺省实现转发该请求。3.适用性在以下条件下使用Responsibility链:有多个的对象可以处理一个请求,哪个对象处理该请求运行
11、时刻自动确定。?你想在不明确指定接收者的情况下,向多个对 象中的一个提交一 个请求。?可处理一个请求的对象集合应被动态指定O4. 结构一个典型的对象结构可能如以下图所示:5. 参与者? H a n d l e r (如H e l p H a n d l e r )一定义一个处理请求的接口。一(可选)实现后继链。? C o n c r e t e H a n d l e r(如 P r i n t B u t t o n 和 P r i n t D i a l o g ) 处理它所负责的请求。一可访问它的后继者。一如果可处理该请求,就处理之;否那么将该请求转发给它的后继者。? C l i e n
12、 t150迓升模武:可夏用面向对象辍件的根底向链上的具体处理者C o n c r e t e H a n d l e r 对象提交请求。6. 协作?当客户提交一个请求时,请求沿链传递直至有一个ConcreteHandler对象负责处理它。7. 效果Responsibility链有以下优点和缺点l i a b i l i t i e s : 1 降低耦合度 该模式使得一 个对象无需知道是其他哪一个对象处理其请求。对象仅需知道该请求会被 正确地处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需知道链的结构。结果是,职责链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用, 而不需保
13、持它所有的候选接受者的引用。2增强了给对象指派职责R e s p o n s i b i l i t y 的灵活性 当在对象中分派职责时, 职责链给你更多的灵活性。你可以通过在运行时刻对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责。你可以将这种机制与静态的特例化处理对象的继承机制结合起来使用。3不保证被接受既然一个请求没有明确的接收者,那么就不能保证它一定会被处理一该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。8. 实现下面是在职责链模式中要考虑的实现问题:1实现后继者链有两种方法可以实现后继者链。a定义新的链接通常在H a n d l e
14、 r中定义,但也可由 ConcreteHandlers来定义。b使用已有的链接。Wi d g e t结我们的例子中定义了新的链接,但你常常可使用已有的对象引用来形成后继者链。例如,在一个局部一整体层次结构中,父构件引用可定义一个部件的后继者。窗口组件构可能早已有这样的链接。C o m p o s i t e 4.3更详细地讨论了父构件引用当已有的链接能够支持你所需的链时,完全可以使用它们。 这样你不需要明确定义链接,而且可以节省空间。但如果该结构不能反映应用所需的职责链,那么你必须定义额外的链接。2连接后继者如果没有已有的引用可定义一个链,那么你必须自己引入它们。这种情况下H a n d l e r不仅定义该请求的接口,通常也维护后继链接。这样H a n d l e r就提供了 H a n d l eR e q u e s t的缺省实现:H a n d l e R e q u e s t向后继者如果有的话 转发请求。如果