参考书籍:设计模式-可复用面向对象软件基础(黑皮书)

目的:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿这条链传递该请求,直到有一个对象处理它为止。

应用:QT的槽机制

类型:行为模式

类图

动机:每个新事物的出现必定有其原因,究其原因就可以找到新事物的本质。

传统的请求处理代码

public void test(int i, Request request){
if(i==1){
Handler1.response(request);
}else if(i == 2){
Handler2.response(request);
}else if(i == 3){
Handler3.response(request);
}else if(i == 4){
Handler4.response(request);
}else{
Handler5.response(request);
}
}

代码的业务逻辑是这样的,方法有两个参数:整数i和一个请求request,根据i的值来决定由谁来处理request,如果i1,由Handler1来处理,如果i2,由Handler2来处理,以此类推。在编程中,这种处理业务的方法非常常见,所有处理请求的类有if…else…条件判断语句连成一条责任链来对请求进行处理,相信大家都经常用到。这种方法的优点是非常直观,简单明了,并且比较容易维护,但是这种方法也存在着几个比较令人头疼的问题:

  • 代码臃肿:实际应用中的判定条件通常不是这么简单地判断是否为1或者是否为2,也许需要复杂的计算,也许需要查询数据库等等,这就会有很多额外的代码,如果判断条件再比较多,那么这个if…else…语句基本上就没法看了。
  • 耦合度高:如果我们想继续添加处理请求的类,那么就要继续添加else if判定条件;另外,这个条件判定的顺序也是写死的,如果想改变顺序,那么也只能修改这个条件语句。

    这样做的缺点我们已经清楚了,就要想办法来解决。这个场景的业务逻辑很简单:如果满足条件1,则由Handler1来处理,不满足则向下传递;如果满足条件2,则由Handler2来处理,不满足则继续向下传递,以此类推,直到条件结束。其实改进的方法也很简单,就是把判定条件的部分放到处理类中,这就是责任链模式的原理。

责任连模式的类图非常简单,它由一个抽象地处理类和它的一组实现类组成:

  • 抽象处理类:抽象处理类中主要包含一个指向下一处理类的成员变量nextHandler和一个处理请求的方法handRequest,handRequest方法的主要主要思想是,如果满足处理的条件,则有本处理类来进行处理,否则由nextHandler来处理。
  • 具体处理类:具体处理类主要是对具体的处理逻辑和处理的适用条件进行实现。

责任链模式处理上述问题的代码实现

任务等级类(与模式无关,只是搭配模式实现效果)

package ChainOfResponsibilityPattern;
public class Level {
private int level = 0;
public Level(int level){
this.level = level;
};
public boolean above(Level level){
if(this.level >= level.level){
return true;
}
return false;
}
}

请求类(与模式无关,只是为了搭配模式实现责任链的输入)

package ChainOfResponsibilityPattern;
public class Request {
Level level;
public Request(Level level){
this.level = level;
}
public Level getLevel(){
return level;
}
}

响应类(与模式无关,只是为了搭配模式实现责任链的输出)

package ChainOfResponsibilityPattern;
public class Response { }

关键类:抽象处理类

package ChainOfResponsibilityPattern;
public abstract class Handler {
private Handler nextHandler;
public final Response handleRequest(Request request){
Response response = null;
if(this.getHandlerLevel().above(request.getLevel())){
response = this.response(request);
}else{
if(this.nextHandler != null){
this.nextHandler.handleRequest(request);
}else{
System.out.println("------没有合适的处理器------");
}
}
return response;
}
public void setNextHandler(Handler handler){
this.nextHandler = handler;
}
protected abstract Level getHandlerLevel();
public abstract Response response(Request request);
}

具体处理类

package ChainOfResponsibilityPattern.ConcreteHandler;
import ChainOfResponsibilityPattern.Handler;
import ChainOfResponsibilityPattern.Level;
import ChainOfResponsibilityPattern.Request;
import ChainOfResponsibilityPattern.Response;
public class ConcreteHandler1 extends Handler {
protected Level getHandlerLevel() {
return new Level(1);
} public Response response(Request request) {
System.out.println("------请求处理器1进行处理------");
return null;
} }
package ChainOfResponsibilityPattern.ConcreteHandler;
import ChainOfResponsibilityPattern.Handler;
import ChainOfResponsibilityPattern.Level;
import ChainOfResponsibilityPattern.Request;
import ChainOfResponsibilityPattern.Response;
public class ConcreteHandler2 extends Handler{
protected Level getHandlerLevel() {
return new Level(2);
} public Response response(Request request) {
System.out.println("------请求处理器2进行处理------");
return null;
}
}
package ChainOfResponsibilityPattern.ConcreteHandler;
import ChainOfResponsibilityPattern.Handler;
import ChainOfResponsibilityPattern.Level;
import ChainOfResponsibilityPattern.Request;
import ChainOfResponsibilityPattern.Response;
public class ConcreteHandler3 extends Handler{
protected Level getHandlerLevel() {
return new Level(3);
}
public Response response(Request request) {
System.out.println("------请求处理器3进行处理------");
return null;
}
}

客户端:测试类

package ChainOfResponsibilityPattern;
import ChainOfResponsibilityPattern.ConcreteHandler.ConcreteHandler1;
import ChainOfResponsibilityPattern.ConcreteHandler.ConcreteHandler2;
import ChainOfResponsibilityPattern.ConcreteHandler.ConcreteHandler3;
public class Client {
public static void main(String[] args) {
//构造处理实例
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
//构造责任链
handler1.setNextHandler(handler2);
handler2.setNextHandler(handler3);
//配槽
Response response = handler1.handleRequest(new Request(new Level(4)));
}
}

代码中Level类是模拟判定条件;Request,Response分别对应请求和响应;抽象类Handler中主要进行条件的判断,这里模拟一个处理等级,只有处理类的处理等级高于Request的等级才能处理,否则交给下一个处理者处理。在Client类中设置好链的前后执行关系,执行时将请求交给第一个处理类,这就是责任连模式,它完成的功能与前文中的if…else…语句是一样的。

责任链模式的优缺点

责任链模式与if…else…相比,他的耦合性要低一些,因为它把条件判定都分散到了各个处理类中,并且这些处理类的优先处理顺序可以随意设定。责任链模式也有缺点,这与if…else…语句的缺点是一样的,那就是在找到正确的处理类之前,所有的判定条件都要被执行一遍,当责任链比较长时,性能问题比较严重。

责任链模式的适用场景

就像开始的例子那样,假如使用if…else…语句来组织一个责任链时感到力不从心,代码看上去很糟糕时,就可以使用责任链模式来进行重构。

总结

责任链模式其实就是一个灵活版的if…else…语句,它就是将这些判定条件的语句放到了各个处理类中,这样做的优点是比较灵活了,但同样也带来了风险,比如设置处理类前后关系时,一定要特别仔细,搞对处理类前后逻辑的条件判断关系,并且注意不要在链中出现循环引用的问题。

ChainOfResponsibilityPattern(23种设计模式之一)的更多相关文章

  1. Java开发中的23种设计模式详解

    [放弃了原文访问者模式的Demo,自己写了一个新使用场景的Demo,加上了自己的理解] [源码地址:https://github.com/leon66666/DesignPattern] 一.设计模式 ...

  2. Java开发中的23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  3. Java开发中的23种设计模式(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  4. c#中的23种设计模式

    C# 23种设计模式汇总 创建型模式 工厂方法(Factory Method) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节.工厂方法模式的核 ...

  5. Java 23种设计模式

    转自: http://zz563143188.iteye.com/blog/1847029 ; i<count; i++){ list.add(new MailSender()); } } pu ...

  6. 从追MM谈Java的23种设计模式(转)

    从追MM谈Java的23种设计模式    这个是从某个文章转载过来的.但是忘了原文链接.如果知道的,我追加一下. 1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西 ...

  7. java 23种设计模式及具体例子 收藏有时间慢慢看

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...

  8. JAVA:23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  9. 从追MM谈Java的23种设计模式

    从追MM谈Java的23种设计模式 1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯 德基,只管向服务员说“来四个鸡 ...

  10. 23种设计模式全解析 (java版本)

    转自:http://blog.csdn.net/longyulu/article/details/9159589 其中PHP常用的五种设计模式分别为:工厂模式,单例模式,观察者模式,策略模式,命令模式 ...

随机推荐

  1. mongodb 的一些启动命令

    启动命令 nohup /home/sh/local/mongodb-linux-x86_64-rhel62-3.4.0/bin/mongod -dbpath /home/sh/local/mongod ...

  2. Pdnovel 在线阅读体验

    pdnovel是discuz的一款小说阅读插件,本身是用php开发的,数据存储于mysql,小说文本存储于file文件.pdnovel本身已有添加书籍.连载章节的功能,但为了批量添加全本txt书籍又开 ...

  3. Jetty实战(杂七杂八)

    最近开始选择JETTY作为服务器了,乘这现在空闲点学习了些JETTY的部署知识,原来她真的跟TOMCAT很类似,先总结如下: 部署应用方法(下载好jetty); 方法一: 直接将应用的 war包放在j ...

  4. ROS的ovpn设置

    转摘至www.80uncle.com 先下载Win下的openvpn客户端http://openvpn.se/download.html 我的证书是用这个客户端做的openvpn-2.0.9-gui- ...

  5. 第三方登录之微信登录,基于ThinkSDK

    本文基于ThinkSDK,为其补充微信登录demo 增加ThinkSDK的微信第三方登录 阅读本文之前请先了解ThinkSDK的文档 http://www.echomod.com/nexstep/fo ...

  6. Mybatis内部原理与插件原理

    Mybatis的运行分为两大问题,第一部分是读取配置文件保存在Configuration对象中,用以创建SqlSessionFactory,第二部分是SqlSession的执行过程.相对而言SqlSe ...

  7. Linux 之 inotify+rsync 备份文件系统

    一.需求 1.线上有不同的机房,并且每个机房所对公网开放端口不一样. 2.A机房中的a机器是台文件服务器,需要备份到B机房中的b机器,以及C机房中的c机器. 3.并且保持实时同步.只要a上面的文件有改 ...

  8. linux下安装mysql后 sql区分大小写

    Linux下的MySQL默认是区分表名大小写的,通过如下设置,可以让MySQL不区分表名大小写:1.用root登录,修改 /etc/my.cnf:2.在[mysqld]节点下,加入一行: lower_ ...

  9. LeetCode题解 #12 Integer to Roman

    题目大意:给定数字,将其转化为罗马数字的形式 罗马数字其实只有 I V X L C D M 这几种形式,其余均为组合的,去百度了解一下就ok. 所以首先想到的就是,将个.十.百.千位的数字构造出来,然 ...

  10. OpenLayers 3 之 切换图层控件

    OpenLayers 3 之 切换图层控件 openlayers 3中并没有默认的图层切换控件,GitHub中有一个项目实现了我们需要的控件-------- ol3-layerswitcher . 可 ...