23.2  解决方案

23.2.1  职责链模式来解决

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

(1)职责链模式定义

 

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

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

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

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

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

23.2.2  模式结构和说明

职责链模式的结构如图23.1所示:

 

图23.1  职责链模式结构图

Handler

       定义职责的接口,通常在这里定义处理请求的方法,可以在这里实现后继链。

ConcreteHandler

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

Client

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

23.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();

    }

}

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

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

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

 

图23.2  使用职责链模式的示例程序的结构示意图

(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元的请求

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

(4)如何运行的

       理解了示例的整体结构和具体实现,那么示例的具体运行过程是怎样的呢?

下面就以“小李申请聚餐费用1200元”这个费用申请为例来说明,调用过程的示意图如图23.3所示:

 

图23.3  职责链示例调用过程示意图

 


---------------------------------------------------------------------------

私塾在线学习网原创内容  跟着cc学设计系列 之 研磨设计模式

研磨设计讨论群【252780326】

原创内容,转载请注明出处【http://sishuok.com/forum/blogPost/list/0/5814.html

---------------------------------------------------------------------------