职责链

1.场景问题

1.1  申请聚餐费用

来考虑这样一个功能:申请聚餐费用的管理。html

不少公司都有这样的福利,就是项目组或者是部门能够向公司申请一些聚餐费用,用于组织项目组成员或者是部门成员进行聚餐活动,以增进人员之间的情感,更有利于工做中的相互合做。java

申请聚餐费用的大体流程通常是:由申请人先填写申请单,而后交给领导审查,若是申请批准下来了,领导会通知申请人审批经过,而后申请人去财务核领费用,若是没有核准,领导会通知申请人审批未经过,此事也就此做罢了。数据库

       不一样级别的领导,对于审批的额度是不同的,好比:项目经理只能审批500元之内的申请;部门经理能审批1000元之内的申请;而总经理能够审核任意额度的申请。设计模式

也就是说,当某人提出聚餐费用申请的请求后,该请求会由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,可是提出申请的人并不知道最终会由谁来处理他的请求,通常申请人是把本身的申请提交给项目经理,或许最后是由总经理来处理他的请求,可是申请人并不知道应该由总经理来处理他的申请请求。安全

那么该怎样实现这样的功能呢?ide

1.2  不用模式的解决方案

       分析上面要实现的功能,主要就是要根据申请费用的多少,而后让不一样的领导来进行处理就能够实现了。也就是有点逻辑判断而已,示例代码以下:函数

/**
 * 处理聚餐费用申请的对象
 */
public class FeeRequest {
    /**
     * 提交聚餐费用申请给项目经理
     * @param user 申请人
     * @param fee 申请费用
     * @return 成功或失败的具体通知
     */
    public String requestToProjectManager(String user,double fee){
       String str = "";
       if(fee < 500){
           //项目经理的权限比较小,只能在500之内
           str = this.projectHandle(user, fee);
       }else if(fee < 1000){
           //部门经理的权限只能在1000之内
           str = this.depManagerHandle(user, fee);
       }else if(fee >= 1000){
           //总经理的权限很大,只要请求到了这里,他均可以处理
           str = this.generalManagerHandle(user, fee);
       }
       return str;
    }
    /**
     * 项目经理审批费用申请,参数、返回值和上面是同样的,省略了
     */
    private String projectHandle(String user, double fee) {
       String str = "";
       //为了测试,简单点,只赞成小李的
       if("小李".equals(user)){
           str = "项目经理赞成"+user+"聚餐费用"+fee+"元的请求";
       }else{
           //其它人一概不一样意
           str = "项目经理不一样意"+user+"聚餐费用"+fee+"元的请求";
       }
       return str;
    }
    /**
     * 部门经理审批费用申请,参数、返回值和上面是同样的,省略了
     */
    private String depManagerHandle(String user, double fee) {
       String str = "";
       //为了测试,简单点,只赞成小李申请的
       if("小李".equals(user)){
           str = "部门经理赞成"+user+"聚餐费用"+fee+"元的请求";
       }else{
           //其它人一概不一样意
           str= "部门经理不一样意"+user+"聚餐费用"+fee+"元的请求";
       }
       return str;
    }
    /**
     * 总经理审批费用申请,参数、返回值和上面是同样的,省略了
     */
    private String generalManagerHandle(String user, double fee) {
       String str = "";
      
       //为了测试,简单点,只赞成小李的
       if("小李".equals(user)){
           str = "总经理赞成"+user+"聚餐费用"+fee+"元的请求";
       }else{
           //其它人一概不一样意
           str = "总经理不一样意"+user+"聚餐费用"+fee+"元的请求";
       }
       return str;
    }
}

写个客户端来测试看看效果,示例代码以下:测试

public class Client {
    public static void main(String[] args) {
       FeeRequest request = new FeeRequest();
      
       //开始测试
       String ret1 = request.requestToProjectManager("小李", 300);
       System.out.println("the ret="+ret1);     
       String ret2 = request.requestToProjectManager("小张", 300);
       System.out.println("the ret="+ret2);
      
       String ret3 = request.requestToProjectManager("小李", 600);
       System.out.println("the ret="+ret3);     
       String ret4 = request.requestToProjectManager("小张", 600);
       System.out.println("the ret="+ret4);
      
       String ret5 = request.requestToProjectManager("小李", 1200);
       System.out.println("the ret="+ret5);     
       String ret6 = request.requestToProjectManager("小张", 1200);
       System.out.println("the ret="+ret6);
    }
}

运行结果以下:this

the ret1=项目经理赞成小李聚餐费用300.0元的请求
the ret2=项目经理不一样意小张聚餐费用300.0元的请求
the ret3=部门经理赞成小李聚餐费用600.0元的请求
the ret4=部门经理不一样意小张聚餐费用600.0元的请求
the ret5=总经理赞成小李聚餐费用1200.0元的请求
the ret6=总经理不一样意小张聚餐费用1200.0元的请求

1.3  有何问题

上面的实现很简单,基本上没有什么特别的难度。仔细想一想,这么实现有没有问题呢?仔细分析申请聚餐费用的业务功能和目前的实现,主要面临着以下问题:spa

  • 聚餐费用申请的处理流程是可能会变更的。
        好比如今的处理流程是:提交申请给项目经理,看看是否适合由项目经理处理,若是不是à看看是否适合由部门经理处理,若是不是à总经理处理的步骤。从此可能会变化成:直接提交给部门经理,看看是否适合由部门经理处理,若是不是à总经理处理这样的步骤。也就是说,对于聚餐费用申请,要求处理的逻辑步骤是灵活的。

  • 各个处理环节的业务处理也是会变更的。
        由于处理流程可能发生变化,也会致使某些步骤的具体的业务功能发生变化,好比:本来部门经理审批聚餐费用的时候,只是判断是否批准;如今,部门经理可能在审批聚餐费用的时候,核算本部门的实时成本,这就出现新的业务处理功能了。

若是采用上面的实现,要是处理的逻辑发生了变化,解决的方法,一个是生成一个子类,覆盖requestToProjectManager方法,而后在里面实现新的处理;另一个方法就是修改处理申请的方法的源代码来实现。要是具体处理环节的业务处理的功能发生了变化,那就只好找到相应的处理方法,进行源代码修改了。

总之都不是什么好方法,也就是说,若是出现聚餐费用申请的处理流程变化的状况,或者是出现各个处理环节的功能变化的时候,上面的实现方式是很难灵活的变化来适应新功能的要求的。

       把上面的问题抽象一下:客户端发出一个请求,会有不少对象均可以来处理这个请求,并且不一样对象的处理逻辑是不同的。对于客户端而言,无所谓谁来处理,反正有对象处理就能够了。

       并且在上述处理中,还但愿处理流程是能够灵活变更的,而处理请求的对象须要能方便的修改或者是被替换掉,以适应新的业务功能的须要。

2  解决方案

2.1  职责链模式来解决

用来解决上述问题的一个合理的解决方案,就是使用职责链模式。那么什么是职责链模式呢?

(1)职责链模式定义

wKioL1lkh5XjKNpwAAB4a4z1y0I487.png

(2)应用职责链模式来解决的思路

当客户端提出一个聚餐费用的申请,后续处理这个申请的对象,项目经理、部门经理和总经理,天然的造成了一个链,从项目经理à部门经理à总经理,客户端的申请请求就在这个链中传递,直到有领导处理为止。看起来,上面的功能要求很适合采用职责链来处理这个业务。

要想让处理请求的流程能够灵活的变更,一个基本的思路,那就是动态构建流程步骤,这样随时均可以从新组合出新的流程来。而要让处理请求的对象也要很灵活,那就要让它足够简单,最好是只实现单一的功能,或者是有限的功能,这样更有利于修改和复用。

       职责链模式就很好的体现了上述的基本思路,首先职责链模式会定义一个全部处理请求的对象都要继承实现的抽象类,这样就有利于随时切换新的实现;其次每一个处理请求对象只实现业务流程中的一步业务处理,这样使其变得简单;最后职责链模式会动态的来组合这些处理请求的对象,把它们按照流程动态组合起来,并要求它们依次调用,这样就动态的实现了流程。

这样一来,若是流程发生了变化,只要从新组合就行了;若是某个处理的业务功能发生了变化,一个方案是修改该处理对应的处理对象,另外一个方案是直接提供一个新的实现,而后在组合流程的时候,用新的实现替换掉旧的实现就能够了。

2.2  模式结构和说明

wKioL1lkiUrD64JLAABq2xHDQ5c214.png

Handler

       定义职责的接口,一般在这里定义处理请求的方法,能够在这里实现后继链。

ConcreteHandler

       实现职责的类,在这个类里面,实现对在它职责范围内请求的处理,若是不处理,就继续转发请求给后继者。

Client

       职责链的客户端,向链上的具体处理者对象提交请求,让职责链负责处理。

2.3  职责链模式示例代码

(1)先来看看职责的接口定义,示例代码以下:

/**
 * 职责的接口,也就是处理请求的接口
 */
public abstract class Handler {
    /**
     * 持有后继的职责对象
     */
    protected Handler successor;
    /**
     * 设置后继的职责对象
     * @param successor 后继的职责对象
     */
    public void setSuccessor(Handler successor) {
       this.successor = successor;
    }
    /**
     * 示意处理请求的方法,虽然这个示意方法是没有传入参数,
     * 但实际是能够传入参数的,根据具体须要来选择是否传递参数
     */
    public abstract void handleRequest();
}

(2)接下来看看具体的职责实现对象,示例代码以下:

/**
 * 具体的职责对象,用来处理请求
 */
public class ConcreteHandler1 extends Handler {
    public void handleRequest() {
       //根据某些条件来判断是否属于本身处理的职责范围
       //判断条件好比:从外部传入的参数,或者这里主动去获取的外部数据,
       //如从数据库中获取等,下面这句话只是个示意
       boolean someCondition = false;
      
       if(someCondition){
           //若是属于本身处理的职责范围,就在这里处理请求
           //具体的处理代码
           System.out.println("ConcreteHandler1 handle request");
       }else{
           //若是不属于本身处理的职责范围,那就判断是否还有后继的职责对象
           //若是有,就转发请求给后继的职责对象
           //若是没有,什么都不作,天然结束
           if(this.successor!=null){
              this.successor.handleRequest();
           }
       }
    }
}

另一个ConcreteHandler2和上面ConcreteHandler1的示意代码几乎是同样的,所以就不去赘述了

(3)接下来看看客户端的示意,示例代码以下:

/**
 * 职责链的客户端,这里只是个示意
 */
public class Client {
    public static void main(String[] args) {
       //先要组装职责链
       Handler h1 = new ConcreteHandler1();
       Handler h2 = new ConcreteHandler2();
      
       h1.setSuccessor(h2);    
       //而后提交请求
       h1.handleRequest();
    }
}

2.4  使用职责链模式重写示例

要使用职责链模式来重写示例,仍是先来实现以下的功能:当某人提出聚餐费用申请的请求后,该请求会在项目经理à部门经理à总经理这样一条领导处理链上进行传递,发出请求的人并不知道谁会来处理他的请求,每一个领导会根据本身的职责范围,来判断是处理请求仍是把请求交给更高级的领导,只要有领导处理了,传递就结束了。

须要把每位领导的处理独立出来,实现成单独的职责处理对象,而后为它们提供一个公共的、抽象的父职责对象,这样就能够在客户端来动态的组合职责链,实现不一样的功能要求了。仍是看一下示例的总体结构,会有助于对示例的理解和把握。如图所示:

wKiom1lkifzA4UTYAADf5IWzjrc426.png

(1)定义职责的抽象类

       首先来看看定义全部职责的抽象类,也就是全部职责的外观,在这个类里面持有下一个处理请求的对象,同时还要定义业务处理方法,示例代码以下:

/**
 * 定义职责对象的接口
 */
public abstract class Handler {
    /**
     * 持有下一个处理请求的对象
     */
    protected Handler successor = null;
    /**
     * 设置下一个处理请求的对象
     * @param successor 下一个处理请求的对象
     */
    public void setSuccessor(Handler successor){
       this.successor = successor;
    }
    /**
     * 处理聚餐费用的申请
     * @param user 申请人
     * @param fee 申请的钱数
     * @return 成功或失败的具体通知
     */
    public abstract String handleFeeRequest(String user,double fee);
}

(2)实现各自的职责

       如今实现的处理聚餐费用流程是:申请人提出的申请交给项目经理处理,项目经理的处理权限是500元之内,超过500元,把申请转给部门经理处理,部门经理的处理权限是1000元之内,超过1000元,把申请转给总经理处理。

       分析上述流程,对请求主要有三个处理环节,把它们分别实现成为职责对象,一个对象实现一个环节的处理功能,这样就会比较简单。

先看看项目经理的处理吧,示例代码以下:

public class ProjectManager extends Handler{
    public String handleFeeRequest(String user, double fee) {
       String str = "";
       //项目经理的权限比较小,只能在500之内
       if(fee < 500){
           //为了测试,简单点,只赞成小李的
           if("小李".equals(user)){
              str = "项目经理赞成"+user+"聚餐费用"+fee+"元的请求";
           }else{
              //其它人一概不一样意
              str = "项目经理不一样意"+user+"聚餐费用"+fee+"元的请求";
           }
           return str;
       }else{
           //超过500,继续传递给级别更高的人处理
           if(this.successor!=null){
              return successor.handleFeeRequest(user, fee);
           }
       }
       return str;
    }
}

接下来看看部门经理的处理,示例代码以下:

public class DepManager extends Handler{ 
    public String handleFeeRequest(String user, double fee) {
       String str = "";
       //部门经理的权限只能在1000之内
       if(fee < 1000){
           //为了测试,简单点,只赞成小李申请的
           if("小李".equals(user)){
              str = "部门经理赞成"+user+"聚餐费用"+fee+"元的请求";
           }else{
              //其它人一概不一样意
              str = "部门经理不一样意"+user+"聚餐费用"+fee+"元的请求";
           }
           return str;
       }else{
           //超过1000,继续传递给级别更高的人处理
           if(this.successor!=null){
              return this.successor.handleFeeRequest(user, fee);
           }
       }
       return str;
    }
}

再看总经理的处理,示例代码以下:

public class GeneralManager extends Handler{
    public String handleFeeRequest(String user, double fee) {
       String str = "";
       //总经理的权限很大,只要请求到了这里,他均可以处理
       if(fee >= 1000){
           //为了测试,简单点,只赞成小李的
           if("小李".equals(user)){
              str = "总经理赞成"+user+"聚餐费用"+fee+"元的请求";
           }else{
              //其它人一概不一样意
              str = "总经理不一样意"+user+"聚餐费用"+fee+"元的请求";
           }
           return str;
       }else{
           //若是还有后继的处理对象,继续传递
           if(this.successor!=null){
              return successor.handleFeeRequest(user, fee);
           }
       }
       return str;
    }
}

(3)使用职责链

那么客户端如何使用职责链呢,最重要的就是要先构建职责链,而后才能使用。示例代码以下:

public class Client {
    public static void main(String[] args) {
       //先要组装职责链   
       Handler h1 = new GeneralManager();
       Handler h2 = new DepManager();
       Handler h3 = new ProjectManager();
       h3.setSuccessor(h2);
       h2.setSuccessor(h1);
      
       //开始测试
       String ret1 = h3.handleFeeRequest("小李", 300);
       System.out.println("the ret1="+ret1); 
       String ret2 = h3.handleFeeRequest("小张", 300);
       System.out.println("the ret2="+ret2); 
      
       String ret3 = h3.handleFeeRequest("小李", 600);
       System.out.println("the ret3="+ret3); 
       String ret4 = h3.handleFeeRequest("小张", 600);
       System.out.println("the ret4="+ret4); 
      
       String ret5 = h3.handleFeeRequest("小李", 1200); 
       System.out.println("the ret5="+ret5); 
       String ret6 = h3.handleFeeRequest("小张", 1200);
       System.out.println("the ret6="+ret6); 
    }
}

运行结果以下:

the ret1=项目经理赞成小李聚餐费用300.0元的请求
the ret2=项目经理不一样意小张聚餐费用300.0元的请求
the ret3=部门经理赞成小李聚餐费用600.0元的请求
the ret4=部门经理不一样意小张聚餐费用600.0元的请求
the ret5=总经理赞成小李聚餐费用1200.0元的请求
the ret6=总经理不一样意小张聚餐费用1200.0元的请求

看起来结果跟前面不用模式的实现方案的运行结果是同样的,它们原本就是实现的一样的功能,只不过实现方式不一样而已。

3.1功能链

在实际开发中,常常会出现一个把职责链稍稍变形的用法。在标准的职责链中,一个请求在职责链中传递,只要有一个对象处理了这个请求,就会中止。

如今稍稍变一下,改为一个请求在职责链中传递,每一个职责对象负责处理请求的某一方面的功能,处理完成后,不是中止,而是继续向下传递请求,当请求经过不少职责对象处理事后,功能也就处理完了,把这样的职责链称为功能链。

考虑这样一个功能,在实际应用开发中,在进行业务处理以前,一般须要进行权限检查、通用数据校验、数据逻辑校验等处理,而后才开始真正的业务逻辑实现。能够把这些功能分散到一个功能链中,这样作的目的是使程序结构更加灵活,并且复用性会更好,好比通用的权限检查就只须要作一份,而后就能够在多个功能链中使用了。

有些朋友看到这里,可能会想,这不是可使用装饰模式来实现吗?没错,可使用装饰模式来实现这样的功能,可是职责链会更灵活一些,由于装饰模式是在已有的功能上增长新的功能,多个装饰器之间会有必定的联系;而职责链模式的各个职责对象实现的功能,相互之间是没有关联的,是本身实现属于本身处理的那一份功能。

可能有些朋友会想到这很相似于在Web应用开发中的过滤器Filter,没错,过滤器链就相似于一个功能链,每一个过滤器负责本身的处理,而后转交给下一个过滤器,直到把全部的过滤器都走完,而后进入到Servlet里面进行处理。最多见的过滤器功能,好比权限检查、字符集转换等,基本上都是Web应用的标配。

接下来在示例中,实现这样的功能:实现商品销售的业务处理,在真正进行销售的业务处理以前,须要对传入处理的数据,进行权限检查、通用数据检查和数据逻辑检查,只有这些检查都能经过的状况下,才说明传入的数据是正确的、有效的数据,才能够进行真正的业务功能处理。

(1)首先定义已有的业务功能和封装业务数据的对象,用前面出现过的那个保存销售信息的业务,为了简单,就不去定义接口了,示例代码以下:

/**
 * 商品销售管理模块的业务处理
 */
public class GoodsSaleEbo {
    /**
     * 保存销售信息,原本销售数据应该是多条,太麻烦了,为了演示,简单点
     * @param user 操做人员
     * @param customer 客户
     * @param saleModel 销售数据
     * @return 是否保存成功
     */
    public boolean sale(String user,String customer
,SaleModel saleModel){
       //若是所有在这里处理,基本的顺序是
       //1:权限检查
       //2:通用数据检查(这个也可能在表现层已经做过了)
       //3:数据逻辑校验
       
       //4:真正的业务处理
       
       //可是如今经过功能链来作,这里就主要负责构建链
       //暂时尚未功能链,等实现好了各个处理对象再回来添加
       return true;
    }
}

对应的封装销售数据的对象,示例代码以下:

/**
 * 封装销售单的数据,简单的示意一下
 */
public class SaleModel {
    /**
     * 销售的商品
     */
    private String goods;
    /**
     * 销售的数量
     */
    private int saleNum;
    public String getGoods() {
       return goods;
    }
    public void setGoods(String goods) {
       this.goods = goods;
    }
    public int getSaleNum() {
       return saleNum;
    }
    public void setSaleNum(int saleNum) {
       this.saleNum = saleNum;
    }
    public String toString(){
       return "商品名称="+goods+",销售数量="+saleNum;
    }
}

(2)定义一个用来处理保存销售数据功能的职责对象的接口,示例代码以下:

/**
 * 定义职责对象的接口
 */
public abstract class SaleHandler {
    /**
     * 持有下一个处理请求的对象
     */
    protected SaleHandler successor = null;
    /**
     * 设置下一个处理请求的对象
     * @param successor 下一个处理请求的对象
     */
    public void setSuccessor(SaleHandler successor){
       this.successor = successor;
    }
    /**
     * 处理保存销售信息的请求
     * @param user 操做人员
     * @param customer 客户
     * @param saleModel 销售数据
     * @return 是否处理成功
     */
    public abstract boolean sale(String user,String customer,
SaleModel saleModel);
}

(3)实现各个职责处理对象,每一个职责对象负责请求的一个方面的处理,把这些职责对象都走完了,功能也就实现完了。先定义处理安全检查的职责对象,示例代码以下:

/**
 * 进行权限检查的职责对象
 */
public class SaleSecurityCheck extends SaleHandler{
    public boolean sale(String user, String customer
, SaleModel saleModel) {
       //进行权限检查,简单点,就小李能经过
       if("小李".equals(user)){
           return this.successor.sale(user, customer, saleModel);
       }else{
           System.out.println("对不起"+user
+",你没有保存销售信息的权限");
           return false;
       }     
    }
}

接下来定义通用数据检查的职责对象,示例代码以下:

/**
 * 进行数据通用检查的职责对象
 */
public class SaleDataCheck extends SaleHandler{
    public boolean sale(String user, String customer
, SaleModel saleModel) {
       //进行数据通用检查,稍麻烦点,每一个数据都要检测
       if(user==null || user.trim().length()==0){
           System.out.println("申请人不能为空");
           return false;
       }
       if(customer==null || customer.trim().length()==0){
           System.out.println("客户不能为空");
           return false;
       }
       if(saleModel==null ){
           System.out.println("销售商品的数据不能为空");
           return false;
       }
       if(saleModel.getGoods() == null
|| saleModel.getGoods().trim().length()==0){
           System.out.println("销售的商品不能为空");
           return false;
       }
       if(saleModel.getSaleNum()==0){
           System.out.println("销售商品的数量不能为0");
           return false;
       }     
       //若是经过了上面的检测,那就向下继续执行
       return this.successor.sale(user, customer, saleModel);
    }
}

再看看进行数据逻辑检查的职责对象,示例代码以下:

/**
 * 进行数据逻辑检查的职责对象
 */
public class SaleLogicCheck extends SaleHandler{
    public boolean sale(String user, String customer
, SaleModel saleModel) {
       //进行数据的逻辑检查,好比检查ID的惟一性,主外键的对应关系等等
       //这里应该检查这种主外键的对应关系,好比销售商品是否存在
       //为了演示简单,直接经过吧
      
       //若是经过了上面的检测,那就向下继续执行
       return this.successor.sale(user, customer, saleModel);
    }
}

最后是真正的业务处理的职责对象,示例代码以下:

/**
 * 真正处理销售的业务功能的职责对象
 */
public class SaleMgr extends SaleHandler{
    public boolean sale(String user, String customer
, SaleModel saleModel) {
       //进行真正的业务逻辑处理
       System.out.println(user+"保存了"+customer
+"购买 "+saleModel+" 的销售数据");
       return true;
    }
}

(4)实现好了各个职责对象处理,回过头来看看如何具体实现业务处理,在业务对象里面进行功能链的组合,示例代码以下:

public class GoodsSaleEbo {
    /**
     * 保存销售信息,原本销售数据应该是多条,太麻烦了,为了演示,简单点
     * @param user 操做人员
     * @param customer 客户
     * @param saleModel 销售数据
     * @return 是否保存成功
     */
    public boolean sale(String user,String customer
,SaleModel saleModel){
       //若是所有在这里处理,基本的顺序是
       //1:权限检查
       //2:通用数据检查(这个也可能在表现层已经做过了)
       //3:数据逻辑校验
      
       //4:真正的业务处理
      
       //可是如今经过功能链来作,这里就主要负责构建链
       SaleSecurityCheck ssc = new SaleSecurityCheck();
       SaleDataCheck sdc = new SaleDataCheck();
       SaleLogicCheck slc = new SaleLogicCheck();
       SaleMgr sd = new SaleMgr();
       ssc.setSuccessor(sdc);
       sdc.setSuccessor(slc);
       slc.setSuccessor(sd);
       //向链上的第一个对象发出处理的请求
       return ssc.sale(user, customer, saleModel);
    }
}

(5)写个客户端,调用业务对象,测试一下看看,示例代码以下:

public class Client {
    public static void main(String[] args) {
       //建立业务对象
       GoodsSaleEbo ebo = new GoodsSaleEbo();
       //准备测试数据
       SaleModel saleModel = new SaleModel();
       saleModel.setGoods("张学友怀旧经典");
       saleModel.setSaleNum(10);
      
       //调用业务功能
       ebo.sale("小李", "张三", saleModel);
       ebo.sale("小张", "李四", saleModel);
    }
}

运行一下,试试看,运行结果以下:

小李保存了张三购买 商品名称=张学友怀旧经典,销售数量=10 的销售数据
对不起小张,你没有保存销售信息的权限

3.2 Struts2拦截器实现

Main.java

public class Main {
    public static void main(String[] args) {
        new ActionInvocation().invoke();
    }
}

ActionInvocation.java

import java.util.ArrayList;
import java.util.List;

public class ActionInvocation {
    List<Interceptor> interceptors = new ArrayList<Interceptor>();
    int index = -1; // 来指示循环到了第几个interceptor了
    Action a = new Action();

    public ActionInvocation() // 构造函数
    {
        this.interceptors.add(new FirstInterceptor());
        this.interceptors.add(new SecondInterceptor());
    }

    public void invoke() {
        index++;
        if (index >= this.interceptors.size()) {
            a.execute();
        } else {

            this.interceptors.get(index).intercept(this);
        }
    }
}

Interceptor.java

public interface Interceptor {
    public void intercept(ActionInvocation invocation);
}

FirstInterceptor.java

public class FirstInterceptor implements Interceptor {

    public void intercept(ActionInvocation invocation) {
        System.out.println("第一个拦截器开始");
        invocation.invoke();
        System.out.println("第一个拦截器结束");
    }

}

SecondInterceptor.java

public class SecondInterceptor implements Interceptor {

    public void intercept(ActionInvocation invocation) {
        System.out.println("第二个拦截器开始");
        invocation.invoke();
        System.out.println("第二个拦截器结束");
    }

}

Action.java

public class Action {
    public void execute() {
        System.out.println("执行execute方法!");
    }
}

看下运行结果:

第一个拦截器开始
第二个拦截器开始
执行execute方法!
第二个拦截器结束
第一个拦截器结束

3.3 Filter过滤器实例

      在处理用户的请求时可能要根据不一样的状况对请求添加不一样的处理逻辑,在这时候就能够利用责任链进行设计。当须要添加一个处理逻辑时能够很方便的添加一个处理的节点。如今咱们的需求是处理用户的请求,将用户提交的字符串信息进行层层处理,同时在处理完成以后返回结果时,也要对返回的字符串进行层层处理,而处理返回的状况时其处理的顺序和先前是正好相反的顺序。
      在FilterChain中继承了Filter接口,从而实现了doFilter方法,在FilterChain中又有一个index变量,该变量是用来标记当前访问的是哪个过滤器,这些过滤器是存放在ArrayList中的,这样用户在使用的时候就能够实现本身的过滤器,编写本身的处理逻辑,从而将本身的过滤器添加到ArrayList中,再调用FilterChain的doFilter方法遍历整个责任链。
1)首先创建用户的请求和接收对象Request和Response:

public class Request {    
    String requestStr;    
    
    public String getRequestStr() {    
        return requestStr;    
    }    
    
    public void setRequestStr(String requestStr) {    
        this.requestStr = requestStr;    
    }    
}
public class Response {    
    String responseStr;    
    
    public String getResponseStr() {    
        return responseStr;    
    }    
    
    public void setResponseStr(String responseStr) {    
        this.responseStr = responseStr;    
    }    
}

咱们将处理用户信息的逻辑抽象成为一个个的过滤器,进一步抽象出过滤器接口Filter:

public interface Filter {    
    public void doFilter(Request request, Response response, FilterChain chain);    
    
}

注意在Filte接口中doFilter方法参数中有FilterChain的一个变量,咱们再创建FilterChain类:

import java.util.ArrayList;    
import java.util.List;    
public class FilterChain implements Filter {    
    List<Filter> filters = new ArrayList<Filter>();    
    int index = 0;    
    
    public FilterChain addFilter(Filter f) {    
        this.filters.add(f);    
        return this;    
    }  
    @Override    
    public void doFilter(Request request, Response response, FilterChain chain) {    
        if (index == filters.size())    
            return;    
        Filter f = filters.get(index);    
        index++;    
        f.doFilter(request, response, chain);    
    }    
}

下面咱们编写三个过滤器:

public class HTMLFilter implements Filter {    
    @Override    
    public void doFilter(Request request, Response response,FilterChain chain) {    
        request.requestStr = request.getRequestStr().replace("<", "[")    
                .replace(">", "] --------HTMLFilter");    
        chain.doFilter(request, response, chain);    
        response.responseStr += "--------HTMLFilter";    
    }    
}
public class SesitiveFilter implements Filter {    
    @Override    
    public void doFilter(Request request, Response response, FilterChain chain) {    
        request.requestStr = request.getRequestStr().replace("敏感", "  ")    
                .replace("猫猫", "haha------SesitiveFilter");    
        chain.doFilter(request, response, chain);    
        response.responseStr += "------SesitiveFilter";    
    }    
}
public class FaceFilter implements Filter {    
    @Override    
    public void doFilter(Request request, Response response, FilterChain chain) {    
        request.requestStr = request.getRequestStr().replace(":)",    
                "^V^-------FaceFilter");    
        chain.doFilter(request, response, chain);    
        response.responseStr += "-------FaceFilter";    
    }    
}

测试:

public class Client {  
    public static void main(String[] args) {  
        String message = "敏感词汇,重庆,<script> 躲猫猫 :)";  
        Request request = new Request();  
        request.setRequestStr(message);  
        Response response = new Response();  
        response.setResponseStr("response");  
        FilterChain fc = new FilterChain();  
        fc.addFilter(new HTMLFilter()).addFilter(new SesitiveFilter());  
        fc.doFilter(request, response, fc);  
        System.out.println("request = " + request.getRequestStr());  
        System.out.println("response = " + response.getResponseStr());  
        System.out.println("=====================================");  
        FilterChain fc2 = new FilterChain();  
        fc2.addFilter(new FaceFilter());  
        fc.addFilter(fc2);  
        fc.doFilter(request, response, fc);  
        System.out.println("request = " + request.getRequestStr());  
        System.out.println("response = " + response.getResponseStr());  
    }  
}

运行结果:

request =   词汇,重庆,[script] --------HTMLFilter 躲haha------SesitiveFilter :)  
response = response------SesitiveFilter--------HTMLFilter  
=====================================  
request =   词汇,重庆,[script] --------HTMLFilter 躲haha------SesitiveFilter ^V^-------FaceFilter  
response = response------SesitiveFilter--------HTMLFilter-------FaceFilter

3.3  职责链模式的优缺点

 1. 请求者和接收者松散耦合
    在职责链模式里面,请求者并不知道接收者是谁,也不知道具体如何处理,请求者只是负责向职责链发出请求就能够了。而每一个职责对象也不用管请求者或者是其它的职责对象,只负责处理本身的部分,其它的就交由其它的职责对象去处理。也就是说,请求者和接收者是彻底解耦的。

 2.动态组合职责
    职责链模式会把功能处理分散到单独的职责对象里面,而后在使用的时候,能够动态组合职责造成职责链,从而能够灵活的给对象分配职责,也能够灵活的实现和改变对象的职责。

 3.产生不少细粒度对象
    职责链模式会把功能处理分散到单独的职责对象里面,也就是每一个职责对象只是处理一个方面的功能,要把整个业务处理完,须要大量的职责对象的组合,这会产生大量的细粒度职责对象。

 4.不必定能被处理
    职责链模式的每一个职责对象只负责本身处理的那一部分,所以可能会出现某个请求,把整个链传递完了,都没有职责对象处理它。这就须要在使用职责链模式的时候注意,须要提供默认的处理,而且注意构建的链的有效性。

3.4  相关模式

 职责链模式和组合模式
    这两个模式能够组合使用。
    能够把职责对象经过组合模式来组合,这样能够经过组合对象自动递归的向上调用,由父组件做为子组件的后继,从而造成链。
    这也就是前面提到过的使用外部已有的连接,这种状况在客户端使用的时候,就不用再构造链了,虽然不构造链,可是须要构造组合对象树,是同样的。

 职责链模式和装饰模式
    这两个模式类似,从某个角度讲,能够相互模拟实现对方的功能。
    装饰模式可以动态的给被装饰对象添加功能,要求装饰器对象和被装饰的对象实现相同的接口。而职责链模式能够实现动态的职责组合,标准的功能是有一个对象处理就结束,可是若是处理完本职责不急于结束,而是继续向下传递请求,那么功能就和装饰模式的功能差很少了,每一个职责对象就相似于装饰器,能够实现某种功能。
    并且两个模式的本质也相似,都须要在运行期间动态组合,装饰模式是动态组合装饰器,而职责链是动态组合处理请求的职责对象的链。
    可是从标准的设计模式上来说,这两个模式仍是有较大区别的,这点要注意。首先是目的不一样,装饰模式是要实现透明的为对象添加功能,而职责链模式是要实现发送者和接收者解耦;另一个,装饰模式是无限递归调用的,能够有任意多个对象来装饰功能,可是职责链模式是有一个处理就结束。

职责链模式和策略模式
    这两个模式能够组合使用。
    这两个模式有类似之处,若是把职责链简化到直接就能选择到相应的处理对象,那就跟策略模式的选择差很少,所以能够用职责链来模拟策略模式的功能。只是若是把职责链简化到这个地步,也就不存在链了,也就称不上是职责链了。
    两个模式能够组合使用,能够在职责链模式的某个职责的实现的时候,使用策略模式来选择具体的实现,一样也能够在策略模式的某个策略实现里面,使用职责链模式来实现功能处理。
    同理职责链模式也能够和状态模式组合使用。


转载至:http://sishuok.com/forum/blogPost/list/0/5815.html

   cc老师的设计模式是我目前看过最详细最有实践的教程。

相关文章
相关标签/搜索