- 浏览: 26206 次
- 性别:
- 来自: 成都
最新评论
设计模式之责任链模式,在Gof的《设计模式》巨作里面是被这样定义的:
在比较容易理解的阎宏博士的《JAVA与模式》一书里面,又是这样被定义的:
其实上面两种定义大家仔细阅读后可以发现是共通的。都讲到了一根传递的链条,链条上有很多可以处理责任的对象,并且责任会随链条传递,每个对象都有机会处理这个传递中的责任,直到最终被链条中的某个对象处理掉。
而在《设计模式》里面,给出了以下的适用范围:
我们来看看责任链模式的优缺点:
接下来我们具体来学习责任链模式,他的UML图我想在网上到处可以找到,这里就不累述了,多本设计模式的书籍里所阐述的责任链模式的角色都只有两个: 抽象处理者角色和具体处理者角色,抽象处理者只是为了让所有具体处理者继承一个共同的父类或者实现一个共同的接口。在此重要的是具体处理者,他的内部持有另外一个具体处理者的引用。我们通过如下代码来看。首先是抽象处理者角色:
接下来是具体处理者角色:
最后是我们的client,调用生成具体处理者并执行处理方法。
从上面代码中不难看出,我们在实际处理方法中没有做任何处理,仅仅是判断是否持有下一个处理者的引用,如果没有,那么自己就执行吧(打印几个字而已)。如果还持有下一个处理者引用,那么我就什么都不做,直接交给下一个处理者来办吧。谁叫我们有一个老爸呢?所以在Client代码中我们也看出来了,h1,h2,h3一个推一个,最终推到了h4头上,只有h4对象没有任何处理者的引用,倒霉催的只有自己去打印字符串了。
其实我们还有另外一种方式实现责任链模式,相比这下,下面这种方式应该更好用。我们来看代码。下面这段代码其实也一样,定义了一个抽象处理者角色,在我们具体负责处理业务的代码中,我们传了一个参数叫WorkChain,后面我们会讲到他的用处。
下面代码定义一个责任链对象WorkChain,他实现了抽象处理者Work接口(很奇怪吧,接口中传入这个责任链对象,责任连对象又实现这个借口,绕啊绕啊你就习惯了。)
下面就是具体的处理者的类,三个类结合起来看可能就容易理解点了,
让我们加上测试代码来让其完整吧。
纵观以上测试代码,当我们将ABC三个具体处理者注册进了ch1这个责任链后,我们还将D这个处理者注册进了ch2这个责任链,但是我们之前说到过,责任链也是实现了抽象处理者接口的。所以也可以将责任链看作是一个特殊的处理者。所以我们当然就可以将ch2责任链对象给加到ch1后面去。
而只具体执行逻辑是这样子的,我之前已经完成了往ch1责任链中注册处理者对象的步骤,这时候当我调用了ch1责任链的execute()执行方法的时候,他会去判断它里面的index是否大于我们注册的处理者对象个数,如果大于,就直接return了,否则,就会拿出index下标的处理者,并执行处理方法。而处理方法中又将责任链自身传了进去。而观察具体处理者代码时候,我们可以看到,当满足某个条件是,该处理者就自己处理而不下发了,而没有满足条件的时候,他就调用传入的责任链的execute方法,继续把这个责任传给index+1的那个处理者去执行...整个逻辑就是这样子的。大家仔细的咀嚼消化一下就应该搞掂了。
而以上这个方法来实现责任链有个好处,就是他使用了接口方式来做,让Java的单一继承没有被浪费掉。而且可灵活的配置责任链并且能将多个责任链组合起来使用。
其实java1.0AWT的事件处理机制(事件浮升机制),Tomcat的filter,还有sturts2的interceptor都是用到了责任链模式。有兴趣的童鞋可以研究一下他们的代码。
引用
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
在比较容易理解的阎宏博士的《JAVA与模式》一书里面,又是这样被定义的:
引用
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
其实上面两种定义大家仔细阅读后可以发现是共通的。都讲到了一根传递的链条,链条上有很多可以处理责任的对象,并且责任会随链条传递,每个对象都有机会处理这个传递中的责任,直到最终被链条中的某个对象处理掉。
而在《设计模式》里面,给出了以下的适用范围:
引用
1) 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
2) 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3) 可处理一个请求的对象集合应被动态指定。
2) 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3) 可处理一个请求的对象集合应被动态指定。
我们来看看责任链模式的优缺点:
引用
(优点)
1.责任链模式减低了发出命令的对象和处理命令的对象之间的耦合
2.它允许多与一个的处理者对象根据自己的逻辑来决定哪一个处理者最终处理这个命令。换言之,发出命令的对象只是把命令传给链结构的起始者,而不需要知道到底是链上的哪一个节点处理了这个命令。
3.在处理命令上,允许系统有更多的灵活性。哪一个对象最终处理一个命令可以因为由那些对象参加责任链、以及这些对象在责任链上的位置不同而有所不同。
(缺点)
4.责任链模式要求链上所有的对象都继承自一个共同的父类或者实现一个共通的接口
5.所有责任开始都是从指定的接收者依次传递下去,运行中无法从中间开始传递
1.责任链模式减低了发出命令的对象和处理命令的对象之间的耦合
2.它允许多与一个的处理者对象根据自己的逻辑来决定哪一个处理者最终处理这个命令。换言之,发出命令的对象只是把命令传给链结构的起始者,而不需要知道到底是链上的哪一个节点处理了这个命令。
3.在处理命令上,允许系统有更多的灵活性。哪一个对象最终处理一个命令可以因为由那些对象参加责任链、以及这些对象在责任链上的位置不同而有所不同。
(缺点)
4.责任链模式要求链上所有的对象都继承自一个共同的父类或者实现一个共通的接口
5.所有责任开始都是从指定的接收者依次传递下去,运行中无法从中间开始传递
接下来我们具体来学习责任链模式,他的UML图我想在网上到处可以找到,这里就不累述了,多本设计模式的书籍里所阐述的责任链模式的角色都只有两个: 抽象处理者角色和具体处理者角色,抽象处理者只是为了让所有具体处理者继承一个共同的父类或者实现一个共同的接口。在此重要的是具体处理者,他的内部持有另外一个具体处理者的引用。我们通过如下代码来看。首先是抽象处理者角色:
public abstract class MyHandler { //持有责任链下一个处理者对象。 protected MyHandler successor; //实际每个处理者处理责任的方法。可根据具体需要选择是否传参和传什么参数。 public abstract void handleRequest(); //以下是对MyHandler的set和get方法。以便于对处理者赋值和获取。 public MyHandler getSuccessor() { return successor; } public void setSuccessor(MyHandler successor) { this.successor = successor; } }
接下来是具体处理者角色:
public class HandlerExecute1 extends MyHandler { @Override public void handleRequest() { //我们在这里简单做了一个模拟逻辑, //就是当下一个处理者不为空的时候我们就放弃处理而让下一个处理者来处理。 if (getSuccessor() != null) { System.out.println("放过请求"); getSuccessor().handleRequest(); }else{ System.out.println("处理请求"); } } }
最后是我们的client,调用生成具体处理者并执行处理方法。
public class TestClient { public static void main(String[] args) { MyHandler h1 = new HandlerExecute1(); MyHandler h2 = new HandlerExecute1(); MyHandler h3 = new HandlerExecute1(); MyHandler h4 = new HandlerExecute1(); //Client端设置了h1有下一个处理者h2的引用 //h2有下一个处理者h3的引用,h3有下一个处理者h4的引用 //h4没有任何处理者的引用,根据逻辑,h4会处理对象。 h1.setSuccessor(h2); h2.setSuccessor(h3); h3.setSuccessor(h4); //从h1处理者开始handle对象。 h1.handleRequest(); } }
从上面代码中不难看出,我们在实际处理方法中没有做任何处理,仅仅是判断是否持有下一个处理者的引用,如果没有,那么自己就执行吧(打印几个字而已)。如果还持有下一个处理者引用,那么我就什么都不做,直接交给下一个处理者来办吧。谁叫我们有一个老爸呢?所以在Client代码中我们也看出来了,h1,h2,h3一个推一个,最终推到了h4头上,只有h4对象没有任何处理者的引用,倒霉催的只有自己去打印字符串了。
其实我们还有另外一种方式实现责任链模式,相比这下,下面这种方式应该更好用。我们来看代码。下面这段代码其实也一样,定义了一个抽象处理者角色,在我们具体负责处理业务的代码中,我们传了一个参数叫WorkChain,后面我们会讲到他的用处。
public interface Work { public void execute(WorkChain chain); }
下面代码定义一个责任链对象WorkChain,他实现了抽象处理者Work接口(很奇怪吧,接口中传入这个责任链对象,责任连对象又实现这个借口,绕啊绕啊你就习惯了。)
public class WorkChain implements Work { //成员变量ArrayList里面储存的是所有被注册进来的具体处理者对象。 private ArrayList<Work> workList = new ArrayList<Work>(); //定义一个计数器,用来辅助调用下一个处理者 int index = 0; public void execute(WorkChain chain) { //当计数器大于或等于具体处理者列表,直接返回,防止下标越界。 if(index >= workList.size()) return; //没有越界,则从列表中拿出当前的具体处理者。 Work work = workList.get(index); //下标字增加 index++; //具体处理者具体调用处理方法,传入该责任链对象 work.execute(chain); } //注册具体处理者到责任链的方法。 public WorkChain setWork(Work work) { workList.add(work); return this; } }上面的代码看起来有点难以理解吧,其实就是创建了一个责任链对象,将所有的具体处理者放在这个对象里面。为什么也要实现抽象处理者接口,是为了将自身也看作一个处理者对象,以便于以后的扩展。(例如将这个责任链加在另一个责任链里面作为处理者使用)。
下面就是具体的处理者的类,三个类结合起来看可能就容易理解点了,
public class WorkA implements Work { //处理标识符,便于模拟业务逻辑。 private String indicator; public void execute(WorkChain chain) { System.out.println("A is working now!!!!!"); //当标识符为“executing”,则不再下发责任,直接自己处理终止。 if ("executing".equals(indicator)) { System.out.println("Ok, no need to processing, I'm handling!"); //当标识符不匹配,则还要向下一个具体处理者下发责任。 }else{ //调用了责任链的execute方法,回顾责任链,是获取下一个具体处理者并执行具体方法。 chain.execute(chain); } } //处理标识符的getter和setter方法。 public String getIndicator() { return indicator; } public void setIndicator(String indicator) { this.indicator = indicator; } }
让我们加上测试代码来让其完整吧。
public static void main(String[] args) { //实例化了四个具体处理对象ABCD WorkA wA = new WorkA(); WorkB wB = new WorkB(); WorkC wC = new WorkC(); WorkD wD = new WorkD(); //仅仅为C设置了可以自己处理的表示字段, //意味着到了D对象处理的时候,他不会下发到另一个处理者那里了 wD.setIndicator("executing"); //创建了一个责任链ch1,并以此绑定了A,C,B具体处理者。 //因此此责任链的工作顺序也是A->C->B WorkChain ch1 = new WorkChain(); ch1.setWork(wA).setWork(wC).setWork(wB); //创建了一个责任链对象ch2,并且绑定了D为具体处理者 WorkChain ch2 = new WorkChain(); ch2.setWork(wD); //将责任链ch2绑定到ch1责任链的最后,也就是责任链ch1执行后还需要执行ch2的处理者 ch1.setWork(ch2); //从责任链ch1开始执行 ch1.execute(ch1); } }
纵观以上测试代码,当我们将ABC三个具体处理者注册进了ch1这个责任链后,我们还将D这个处理者注册进了ch2这个责任链,但是我们之前说到过,责任链也是实现了抽象处理者接口的。所以也可以将责任链看作是一个特殊的处理者。所以我们当然就可以将ch2责任链对象给加到ch1后面去。
而只具体执行逻辑是这样子的,我之前已经完成了往ch1责任链中注册处理者对象的步骤,这时候当我调用了ch1责任链的execute()执行方法的时候,他会去判断它里面的index是否大于我们注册的处理者对象个数,如果大于,就直接return了,否则,就会拿出index下标的处理者,并执行处理方法。而处理方法中又将责任链自身传了进去。而观察具体处理者代码时候,我们可以看到,当满足某个条件是,该处理者就自己处理而不下发了,而没有满足条件的时候,他就调用传入的责任链的execute方法,继续把这个责任传给index+1的那个处理者去执行...整个逻辑就是这样子的。大家仔细的咀嚼消化一下就应该搞掂了。
而以上这个方法来实现责任链有个好处,就是他使用了接口方式来做,让Java的单一继承没有被浪费掉。而且可灵活的配置责任链并且能将多个责任链组合起来使用。
其实java1.0AWT的事件处理机制(事件浮升机制),Tomcat的filter,还有sturts2的interceptor都是用到了责任链模式。有兴趣的童鞋可以研究一下他们的代码。
发表评论
-
SpringMVC DispatcherServlet中使用的特殊Bean
2014-04-11 15:52 962看了开涛博客 ... -
Spring中的代理模式 AOP XML实现方法
2014-03-20 00:21 1067前面跟大家描述了一下我们Spring中使用An ... -
Spring中的代理模式 AOP Annotation实现方法
2014-03-19 23:51 2210之前我们有讲过代理模式和动态代理,其实在Spr ... -
浅谈设计模式2 -- 代理模式
2014-03-18 01:49 599说到代理模式,我想从字面意思,应该是最容易理解 ... -
Spring 的配置
2014-03-17 23:46 6261.Web项目引入Spring的方式。(web ... -
XML 解析(二) JDOM, DOM4J,Digester
2014-03-13 02:05 1516延续XML解析的几种方式(一)的代码格式,我们 ... -
XML 解析(一) 原始的DOM和SAX解析(用于理解解析原理)
2014-03-13 00:54 1172我们今天的话题是XML的解析。现在做项目很多时 ... -
Servlet的HttpServletResponse对象
2014-03-08 00:33 2985我们之前说到过, Web服务器收到一个http ... -
Servlet的一些内置对象和配置参数
2014-03-05 00:14 8501.Servlet的内置对象和JSP的内置对象。 ... -
老生常谈 Servlet的一些基本知识
2014-03-04 23:45 503Java Web开发,我们在这里谈到一个简单的 ... -
关于Spring3.x + MyBatis 3.x架构的一点经验
2012-11-12 11:01 1308该文章仅为记录自己第一次构建Spring3.x 和 MyBat ...
相关推荐
- 责任链模式:避免向多个对象分发请求,将请求沿着处理者链传递,直到被处理。 - 命令模式:将请求封装为一个对象,以便于使用不同的请求、队列请求或参数化请求。 - 解释器模式:给定一种语言,定义它的文法...
本文以项目中的一个工作流模块,演示责任链模式、策略模式、命令模式的组合实现!最近在做的一个项目,涉及到的是一个流程性质的需求。关于工程机械行业的服务流程:服务任务流程和备件发运流程。项目之初,需求不是...
**OOP之UML设计模式概述** 面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它以对象为中心,强调数据和操作数据的方法,通过封装、继承和多态等特性来实现软件的模块化和可扩展性。在OOP中...
在《设计模式浅谈24种》中,主要讨论了24种经典的GOF设计模式,这些模式被分为三大类:创建型、结构型和行为型。 创建型模式主要关注对象的创建,包括以下几个核心模式: 1. **Abstract Factory**(抽象工厂)模式...
Java 责任链模式是一种行为型设计模式,它通过提供一个接收者对象的链来处理请求,从而避免了请求发送者和接收者之间的耦合。这使得多个对象都有可能接收请求,并且沿着链传递请求,直到有对象处理它为止。 意图 ...
为了解决这个问题,我们可以采用面向对象设计中的策略模式和责任链模式进行重构。首先,我们定义一个`ShareChannel`接口,该接口包含一个`share`方法,用于执行特定渠道的分享逻辑。接着,针对每个分享渠道(如A...
综上所述,电源企业要建立和维护一个有效的供应商质量管理模式,必须从企业的质量理念、跨部门协作、供应商自主管理、绩效评估、激励制度、安全管理和供应商的引入审核等多个方面着手,确保整个供应链的稳定性和产品...
《浅谈中职学校物流管理专业基于企业需求的教学改革》 物流管理专业作为职业教育中的重要组成部分,其教学模式必须紧跟企业需求,以培养符合行业标准的实用型人才为目标。随着社会经济的发展和产业结构的调整,物流...
1. Apache Commons Chain:是一个命令模式和责任链模式的综合体,提供了一个灵活的方式来管理和执行工作流。 2. 工作流的角色:chain、context和command。 3. Command模式:是一种设计模式,用于定义命令的执行...
本教程共分为5个部分,第一部分是C语言提高部分,第二部分为C++基础部分,第三部分为C++进阶部分,第四部分为C、C++及数据结构基础部分,第五部分为C_C++与设计模式基础,内容非常详细. 第一部分 C语言提高部分目录...