1、第15章 责任链模式(Chain of Responsibility Pattern)行为型模式行为型模式行为型模式概述行为型模式概述 行为型模式行为型模式(Behavioral Pattern)是对是对在不同的对在不同的对象之间划分责任和算法的抽象化象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构,而且行为型模式不仅仅关注类和对象的结构,而且重重点关注它们之间的相互作用点关注它们之间的相互作用。通过行为型模式,可以更加清晰地通过行为型模式,可以更加清晰地划分类与对象划分类与对象的职责的职责,并,并研究系统在运行时实例对象之间的交研究系统在运行时实例对象之间的交互互。在系统运行
2、时,对象并不是孤立的,它们可。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。对象在运行时也将影响到其他对象的运行。行为型模式分为行为型模式分为类行为型模式类行为型模式和和对象行为型模式对象行为型模式两两种:种:类行为型模式类行为型模式:类的行为型模式:类的行为型模式使用继承关系在使用继承关系在几个类之间分配行为几个类之间分配行为,类行为型模式主要通过多,类行为型模式主要通过多态等方式来分配父类与子类的职责。态等方式来分配父类与子类的职责。对象行为型模式对象行为型模式:对象的行为型模
3、式则:对象的行为型模式则使用对象使用对象的聚合关联关系来分配行为的聚合关联关系来分配行为,对象行为型模式主,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的要是通过对象关联等方式来分配两个或多个类的职责。根据职责。根据“合成复用原则合成复用原则”,系统中要尽量使,系统中要尽量使用关联关系来取代继承关系,因此大部分行为型用关联关系来取代继承关系,因此大部分行为型设计模式都属于对象行为型设计模式。设计模式都属于对象行为型设计模式。行为型模式行为型模式行为型模式行为型模式 行为型模式简介行为型模式简介 职责链模式职责链模式(Chain of Responsibility)命令模式命令模式(
4、Command)解释器模式解释器模式(Interpreter)迭代器模式迭代器模式(Iterator)中介者模式中介者模式(Mediator)备忘录模式备忘录模式(Memento)观察者模式观察者模式(Observer)状态模式状态模式(State)策略模式策略模式(Strategy)模板方法模式模板方法模式(Template Method)访问者模式访问者模式(Visitor)职责链模式职责链模式职责链模式职责链模式模式动机模式动机 职责链可以是职责链可以是一条直线、一个环或者一个树一条直线、一个环或者一个树形结构形结构,最常见的职责链是,最常见的职责链是直线型直线型,即沿着,即沿着一条单向
5、的链一条单向的链来传递请求。来传递请求。链上的每一个对象都是请求处理者,职责链链上的每一个对象都是请求处理者,职责链模式可以模式可以将请求的处理者组织成一条链将请求的处理者组织成一条链,并,并使请求沿着链传递,由链上的处理者对请求使请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到理细节以及请求的传递,只需将请求发送到链上即可,链上即可,将请求的发送者和请求的处理者将请求的发送者和请求的处理者解耦解耦。这就是职责链模式的模式动机。这就是职责链模式的模式动机。模式定义模式定义 避免请求发送者与接收
6、者耦合在一起,避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求让多个对象都有可能接收请求,将这些将这些对象连接成一条链对象连接成一条链,并且,并且沿着这条链传沿着这条链传递请求递请求,直到有对象处理它为止。由于,直到有对象处理它为止。由于英文翻译的不同,职责链模式又称为责英文翻译的不同,职责链模式又称为责任链模式,它是一种任链模式,它是一种对象行为型模式对象行为型模式。职责链模式职责链模式责任链模式的责任链模式的UML类结构类结构 抽象处理者(抽象处理者(Handler)角色角色 定义出一个处理请求的接口;如果需要,接定义出一个处理请求的接口;如果需要,接口可以定义出一个方法,以口
7、可以定义出一个方法,以设定和返回对下设定和返回对下家的引用。这个角色通常由一个抽象类或接家的引用。这个角色通常由一个抽象类或接口实现。口实现。具体处理者(具体处理者(ConcreteHandler)角色角色 具体处理者接到请求后,可以选择将请求处具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。体处理者可以访问下家。职责链模式职责链模式模式分析模式分析在职责链模式里,很多对象在职责链模式里,很多对象由每一个对象由每一个对象对其下家的引
8、用而连接起来形成一条链对其下家的引用而连接起来形成一条链。请求在这条链上传递请求在这条链上传递,直到链上的某一个,直到链上的某一个对象处理此请求为止。对象处理此请求为止。发出这个请求的客户端并不知道链上的哪发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得一个对象最终处理这个请求,这使得系统系统可以在不影响客户端的情况下动态地重新可以在不影响客户端的情况下动态地重新组织链和分配责任组织链和分配责任。public abstract class Handler protected Handler successor;public void SetSuccessor(Handler
9、 successor)this.successor=successor;abstract public void HandleRequest(int request);public class ConcreteHandler1 extends Handler public void HandleRequest(int request)if(request=0&request=10&request=20&request 30)System.out.println(handled request:“+request.toString();else if(successor!=null)succes
10、sor.HandleRequest(request);public class Client public static void main(String args)/Setup Chain of Responsibility Handler h1=new ConcreteHandler1();Handler h2=new ConcreteHandler2();Handler h3=new ConcreteHandler3();h1.SetSuccessor(h2);h2.SetSuccessor(h3);/Generate and process request int requests=2
11、,5,14,22,18,3,27,20;foreach(int request in requests)h1.HandleRequest(request);击鼓传花击鼓传花击鼓者将花传给贾母,开始传花游戏。花由贾母传击鼓者将花传给贾母,开始传花游戏。花由贾母传给贾赦,由贾赦传给贾政,由贾政传给贾宝玉,又给贾赦,由贾赦传给贾政,由贾政传给贾宝玉,又由贾宝玉传给贾环,由贾环传回给贾母,如此往复。由贾宝玉传给贾环,由贾环传回给贾母,如此往复。当鼓声停止时,手中有花的人就得执行酒令当鼓声停止时,手中有花的人就得执行酒令.击鼓传花系统的击鼓传花系统的UML类图类图抽象处理者抽象处理者 abstract
12、class Player abstract public void handle(int i);/处理方法 private Player successor;public Player()successor=null;protected void setSuccessor(Player aSuccessor)successor=aSuccessor;public void next(int index)/传递方法 if(successor!=null)successor.handle(index);else System.out.println(Program terminated.);具体处
13、理者具体处理者class JiaMu extends Player public JiaMu(Player aSuccessor)this.setSuccessor(aSuccessor);public void handle(int i)if(i=1)System.out.println(Jia Mu gotta drink!);else System.out.println(Jia Mu passed!);next(i);客户端客户端public class DrumBeater private static Player player;static public void main(St
14、ring args)player=new JiaMu(new JiaShe(new JiaZheng(new JiaBaoYu(new JiaHuan(null);player.handle(4);AWT事件浮升机制事件浮升机制1.1.事件首先传播到它所发生的部件上,然后向事件首先传播到它所发生的部件上,然后向其父类处理器传播。其父类处理器传播。2.2.容器可以选择处理这个事件,或者再将此事容器可以选择处理这个事件,或者再将此事件向更高一级的父类处理器传播。件向更高一级的父类处理器传播。3.3.事件如此一级级地向上传播,就像水底的气事件如此一级级地向上传播,就像水底的气泡一点一点地冒到水面上一
15、样,因此又叫做泡一点一点地冒到水面上一样,因此又叫做事件浮升机制事件浮升机制。AWT库里处理事件的代码库里处理事件的代码 public boolean action(Event event,Object obj)if(event.target=btnOK)doOKBtnAction();else if(event.target=btnExit)doExitBtnAction();else return super.action(event,obj);return true;AWT1.1的事件处理模型于的事件处理模型于1.0相比有了很大的变化。相比有了很大的变化。新的事件处理模型是建立在新的事件
16、处理模型是建立在观察者模式观察者模式的基础之上的,的基础之上的,而不再是而不再是责任链模式责任链模式的基础之上的的基础之上的。AWT库里处理事件的缺点库里处理事件的缺点 AWT1.0AWT1.0的事件处理的模型是基于继承的,会导的事件处理的模型是基于继承的,会导致很多的子类,在一个面向对象的系统里,经致很多的子类,在一个面向对象的系统里,经常使用的应当是委派。常使用的应当是委派。由于每一个事件都会沿着部件树结构向上传播,由于每一个事件都会沿着部件树结构向上传播,因此事件浮升机制会使得事件的处理变得较慢因此事件浮升机制会使得事件的处理变得较慢。举例举例把一个对象在一个链接传递直到被处理。在这个链
17、把一个对象在一个链接传递直到被处理。在这个链上的所有的对象有相同的接口(抽象类)但却有不上的所有的对象有相同的接口(抽象类)但却有不同的实现。同的实现。1.java.util.logging.Logger 方法方法 log()2.Apache Tomcat 的对的对Encoding的处理的处理3.Struts2 的拦截器的拦截器4.jsp servlet 的的Filter5.JavaScript事件浮升机制事件浮升机制Example All small children cause damage,but how should they be punished?Based upon the do
18、llar amount of damage done by the child,the family must decide who is to punish their child.Who in this Chain of Responsibility is to punish the child;The Grandma,the Mother,the Father,or something worse.muwhaahahahaaa.UML Diagram of Chain of responsibilityCodeabstract class KidsPunished public int
19、least=15;public KidsPunished successor;public void setSuccessor(KidsPunished successor)this.successor=successor;abstract public void processRequest(PunishRequest request);More Codeclass Grandma extends KidsPunished public int tolerance=10*least;public void processRequest(PunishRequest request)if(req
20、uest.getAmount()tolerance)System.out.println(Amount is$+request.getAmount()+,so Grandma jobs to punish);else if(successor!=null)successor.processRequest(request);Codeclass Mother extends KidsPunished private final double tolerance=20*least;public void processRequest(PunishRequest request)if(request.
21、getAmount()tolerance)System.out.println(Amount is$+request.getAmount()+,so Moms jobs to punish);else if(successor!=null)successor.processRequest(request);Codeclass Father extends KidsPunished public int tolerance=30*least;public void processRequest(PunishRequest request)if(request.getAmount()toleran
22、ce)System.out.println(Amount is$+request.getAmount()+,so Fathers jobs to punish);else if(successor!=null)successor.processRequest(request);class HigherPower extends KidsPunished public int tolerance=100*least;public void processRequest(PunishRequest request)if(request.getAmount()Director-Vice Presid
23、ent-Presidentabstract class Approver protected final double base=500;protected Approver successor;public void setSuccessor(Approver successor)this.successor=successor;abstract public void processRequest(PurchaseRequest request);class Manager extends Approver private final double ALLOWABLE=10*base;pu
24、blic void processRequest(PurchaseRequest request)if(request.getAmount();double d=Double.parseDouble(new BufferedReader(new InputStreamReader(System.in).readLine();manager.processRequest(new PurchaseRequest(0,d,General);catch(Exception e)System.exit(1);纯的与不纯的责任链模式纯的与不纯的责任链模式 1.一个纯的责任链模式要求一个具体的处理者一个纯的
25、责任链模式要求一个具体的处理者对象只能在对象只能在两个行为中选择一个两个行为中选择一个:一个是承:一个是承担责任,二是把责任推给下家。不允许出现担责任,二是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。后又把责任向下传的情况。2.在一个纯的责任链模式里面,一个请求必须在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;被某一个处理者对象所接收;在一个不纯的在一个不纯的责任链模式里面,一个请求可以最终不被任责任链模式里面,一个请求可以最终不被任何接收端对象所接收。何接收端对象所接收。3.纯的责任链模式的例
26、子是不容易找到的,一纯的责任链模式的例子是不容易找到的,一 般看到的例子均是不纯的责任链模式的实现般看到的例子均是不纯的责任链模式的实现。职责链模式优缺点职责链模式优缺点职责链模式的优点职责链模式的优点 降低耦合度降低耦合度 可简化对象的相互连接可简化对象的相互连接 增强给对象指派职责的灵活性增强给对象指派职责的灵活性 增加新的请求处理类很方便增加新的请求处理类很方便职责链模式的缺点职责链模式的缺点不能保证请求一定被接收。不能保证请求一定被接收。系统性能将受到一定影响,而且在系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会进行代码调试时不太方便;可能会造成循环调用。造成循环调用。职
27、责链模式优缺点职责链模式优缺点有多个对象可以处理同一个请求,有多个对象可以处理同一个请求,具体具体哪个对象处理该请求由运行时刻自动确哪个对象处理该请求由运行时刻自动确定定。在不明确指定接收者的情况下,在不明确指定接收者的情况下,向多个向多个对象中的一个提交一个请求对象中的一个提交一个请求。可可动态指定一组对象处理请求动态指定一组对象处理请求。应用场景应用场景A Decorator usually wraps the decorated object:clients point to the decorator and not the objectA Decorator does not hav
28、e to forward the same messageA decorated object does not have to know that it is wrappedWith a chain of responsibility,the client asks the first chain objects explicitly.38Differences with Decorator In chain of responsibility:you can break the chain at any point Decorators can be thought of as execu
29、ting all at once without any interaction with the other decorators Links in a chain can be thought of as executing one at a time,because they each depend on the previous link39Chain of resposibility vs Decorator1.装饰模式装饰模式也以类似的方式形成一条装饰链也以类似的方式形成一条装饰链 主要目的是减少对象之间的藕合主要目的是减少对象之间的藕合:一个对象只需知道一个对象只需知道如何将请求
30、转发给其他对象。如何将请求转发给其他对象。链中的每个对象都是链中的每个对象都是“自治自治”的,它对其他对象一无所知,只需判断它的,它对其他对象一无所知,只需判断它本身能否满足请求这样,既能独立编写每个对象,本身能否满足请求这样,既能独立编写每个对象,又很容易构建链又很容易构建链.链中的最后一个对象是以默认方链中的最后一个对象是以默认方式处理它收到的所有请求,还是简单地抛弃请求。式处理它收到的所有请求,还是简单地抛弃请求。2.责任链模式责任链模式通常应用于图形用户界面中,窗口中可通常应用于图形用户界面中,窗口中可以包含控件,控件中还可以包含控件。控件收到消以包含控件,控件中还可以包含控件。控件收
31、到消息时,要么处理该消息要么将消息传递给父控件息时,要么处理该消息要么将消息传递给父控件.责任链还会以树状出现,一个事件可以传递给多个责任链还会以树状出现,一个事件可以传递给多个类,多个类也可以将信息提交给一个类类,多个类也可以将信息提交给一个类与装饰模式的比较与装饰模式的比较思考思考每个应用系统都有的登录验证。一般登陆验证有几每个应用系统都有的登录验证。一般登陆验证有几个方面的验证:个方面的验证:1.用户输入参数的验证,如输入参数是否符合输用户输入参数的验证,如输入参数是否符合输入要求,字段长度要求,是否都是合法字符等。入要求,字段长度要求,是否都是合法字符等。2.当前客户端用户的安全检查,
32、用户是否为禁用当前客户端用户的安全检查,用户是否为禁用用户,用户用户,用户IP是否未禁用是否未禁用IP,用户是否被锁定等。,用户是否被锁定等。3.用户权限检查,检查用户是否在系统中存在,用户权限检查,检查用户是否在系统中存在,用户密码是否正确用户密码是否正确某某OA系统需要提供一个假条审批的模块,如果员系统需要提供一个假条审批的模块,如果员工请假天数小于工请假天数小于3天,主任可以审批该假条;如果天,主任可以审批该假条;如果员工请假天数大于等于员工请假天数大于等于3天,小于天,小于10天,经理可以天,经理可以审批;如果员工请假天数大于等于审批;如果员工请假天数大于等于10天,小于天,小于30天
33、,总经理可以审批;如果超过天,总经理可以审批;如果超过30天,总经理也天,总经理也不能审批,提示相应的拒绝信息不能审批,提示相应的拒绝信息。用责任链模式用责任链模式模拟。模拟。第第15次作业次作业successorLeaderabstract#namesuccessor:String:Leader+Leader(String name)setSuccessor(Leader successor)handleRequest(LeaveRequest request).:void:voidDirector+Director(String name)handleRequest(LeaveReques
34、t request).:voidLeaveRequest-leaveNameleaveDays:String:int+LeaveRequest(String leaveName,int leaveDays)setLeaveName(String leaveName)setLeaveDays(int leaveDays)getLeaveName()getLeaveDays().:void:void:String:intManager+Manager(String name)handleRequest(LeaveRequest request).:voidGeneralManager+GeneralManager(String name)handleRequest(LeaveRequest request).:void用责任链模式用责任链模式模拟模拟javascript事件事件冒泡冒泡第第15次作业(次作业(上机题上机题)