责任链模式

什么是责任链模式

  责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

责任链的组成

  抽象处理者角色:定义一个处理请求的接口或者抽象类。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用

  具体处理角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家

应用场景

  申请聚餐费用的管理,申请聚餐费用的大致流程一般是,由申请人先填写申请单,然后交给领导审批,如果申请批准下来,领导会通知申请人审批通过,然后申请人去财务领取费用,如果没有批准下来,领导会通知申请人审批未通过,此事也就此作罢。不同级别的领导,对于审批的额度是不一样的,比如,项目经理只能审批500元以内的申请;部门经理能审批1000元以内的申请;而总经理可以审核任意额度的申请。当某人提出聚餐费用申请的请求后,该请求会经由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,但是提出申请的人并不知道最终会由谁来处理他的请求,一般申请人是把自己的申请提交给项目经理,或许最后是由总经理来处理他的请求。申请人只要直接与项目经理交互就可以,其余的工作在黑盒中,究竟流程是怎样的,最后是由谁审批通过的,申请人无需关心。

简单的例子:

 创建抽象处理角色

package org.burning.sport.design.pattern.chainofresponsibility.one;

public abstract class Leader {
    protected Leader leader;

    public Leader getLeader() {
        return leader;
    }

    public void setLeader(Leader leader) {
        this.leader = leader;
    }

    public abstract String approve(String name, Double money);
}

创建三个具体处理角色,也就是项目经理,部门经理和总经理角色

package org.burning.sport.design.pattern.chainofresponsibility.one;

public class ProjectManager extends Leader {
    @Override
    public String approve(String name, Double money) {
        if("张山".equals(name) && money < 500) {
            return "PM同意" + name + "申请" + money +"元人民币";
        } else {
            if(getLeader() != null) {
                return getLeader().approve(name, money);
            }
        }

        return "项目经理";

    }
}
package org.burning.sport.design.pattern.chainofresponsibility.one;

public class DeptManger extends Leader {
    @Override
    public String approve(String name, Double money) {
        if("张山".equals(name) && (money < 1000 && money >= 500)) {
            return "部门经理同意" + name + "申请" + money + "元人民币";
        } else {
            if(getLeader() != null) {
                return getLeader().approve(name, money);
            }
            return "部门经理";
        }
    }
}
package org.burning.sport.design.pattern.chainofresponsibility.one;

public class AccountManager extends Leader {
    @Override
    public String approve(String name, Double money) {
        if("张山".equals(name) && money >=1000) {
            return "总经理同意" + name + "申请" + money + "元人民币";
        } else {
            if(getLeader() != null) {
                return getLeader().approve(name, money);
            }
            return "总经理";
        }
    }
}

创建客户端

package org.burning.sport.design.pattern.chainofresponsibility.one;

/**
 * 责任链设计模式
 */
public class ClientMain {

    public static void main(String[] args) {
        //组装责任链
        Leader account = new AccountManager();
        Leader dept = new DeptManger();
        Leader pm = new ProjectManager();

        pm.setLeader(dept);
        dept.setLeader(account);

        //开始测试
        String str1 = pm.approve("张山", 300.0);
        System.out.println(str1);
        String str2 = pm.approve("李四", 300.0);
        System.out.println(str2);
        System.out.println("-----------------");

        String str3 = pm.approve("张山", 800.0);
        System.out.println(str3);
        String str4 = pm.approve("李四", 800.0);
        System.out.println(str4);
        System.out.println("------------------");
        String str5 = pm.approve("张山", 1800.0);
        System.out.println(str5);
        String str6 = pm.approve("李四", 1800.0);
        System.out.println(str6);
        System.out.println("------------------");

    }
}

运行结果

PM同意张山申请300.0元人民币
总经理
-----------------
部门经理同意张山申请800.0元人民币
总经理
------------------
总经理同意张山申请1800.0元人民币
总经理
------------------

   应用的例子:

  我们有一个字符串    String msg = ":):,<script>,敏感,被就业,网络授课";    我们希望应用以下三个规则对字符串进行过滤和谐处理:

  1.将字符串中出现的"<>"符号替换成"[]"

  2.处理字符串中的敏感信息,将 “被就业” 和谐 “成就业”

  3.将字符串中出现的 ":):" 转换成 "^V^";

一、定义封装请求的类Request和封装处理结果响应的类Response

package org.burning.sport.design.pattern.chainofresponsibility.two;

/**
 * 封装请求的类Request
 */
public class Request {
    String requestStr;

    public String getRequestStr() {
        return requestStr;
    }

    public void setRequestStr(String requestStr) {
        this.requestStr = requestStr;
    }
}
package org.burning.sport.design.pattern.chainofresponsibility.two;

/**
 * 封装响应信息的类Response
 */
public class Response {
    String responseStr;

    public String getResponseStr() {
        return responseStr;
    }

    public void setResponseStr(String responseStr) {
        this.responseStr = responseStr;
    }
}

二、定义具有过滤功能的接口Filter,具体的过滤规则需要实现该接口

package org.burning.sport.design.pattern.chainofresponsibility.two;

/**
 * 定义接口Filter,具体的过滤规则需要实现这个接口,最后一个参数添加的意义是我们在Main函数中:
 * fc.doFilter(request, response,fc);执行这一步的时候可以按照规则链条一次使用三个过滤规则对字符串进行处理
 */
public interface MyFilter {
    void doFilter(Request request, Response response, MyFilterChain filterChain);
}

三、定义具体的过滤处理规则

规则一

package org.burning.sport.design.pattern.chainofresponsibility.two;

public class HTMLFilter implements MyFilter {
    @Override
    public void doFilter(Request request, Response response, MyFilterChain filterChain) {
        request.requestStr = request.requestStr.replace('<','[').replace('>','}') + "------来自HTMLFilter";
        filterChain.doFilter(request,response,filterChain);
        response.responseStr += "----HTMLFilter()";
    }
}

规则二

package org.burning.sport.design.pattern.chainofresponsibility.two;

public class SensitiveFilter implements MyFilter {
    @Override
    public void doFilter(Request request, Response response, MyFilterChain filterChain) {
        request.requestStr = request.requestStr.replace("被就业", "就业").replace("敏感", "") + "------来自SensitiveFilter";
        filterChain.doFilter(request, response, filterChain);
        response.responseStr += "------sensitiveFilter()";
    }
}

规则三

package org.burning.sport.design.pattern.chainofresponsibility.two;


public class FaceFilter implements MyFilter {
    @Override
    public void doFilter(Request request, Response response, MyFilterChain filterChain) {
        request.requestStr = request.requestStr.replace(":):", "^V^") + "----FaceFilter()";
        filterChain.doFilter(request, response, filterChain);
        response.responseStr += "---FaceFilter()";
    }
}

四、定义责任链FilterChain

package org.burning.sport.design.pattern.chainofresponsibility.two;

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

/**
 * 定义责任链MyFilterChain
 */
public class MyFilterChain implements MyFilter {
    //用List集合来存储过滤规则
    List<MyFilter> filters = new ArrayList<MyFilter>();
    //用于标记规则的引用顺序
    int index = 0;
    //往规则链条中添加规则
    public MyFilterChain addFilter(MyFilter filter) {
        filters.add(filter);
        //代码的设计技巧:Chain链添加过滤规则结束后返回添加后的Chain,方便我们下面doFilter函数的操作
        return this;
    }
    @Override
    public void doFilter(Request request, Response response, MyFilterChain filterChain) {
        //index初始化为0,filters.size()为3,不会执行return操作
        if(index == filters.size()) {
            return;
        }

        //没添加一个过滤规则,index自增
        MyFilter f = filters.get(index);
        index ++;
        //根据索引值获取对应的规律规则对字符串进行处理
        f.doFilter(request, response, filterChain);
    }
}

五、测试

package org.burning.sport.design.pattern.chainofresponsibility.two;

public class ClientMain {
    public static void main(String[] args) {
        String requestStr = ":):,<script>,敏感,被就业,网络授课";
        Request request = new Request();
        request.setRequestStr(requestStr);

        Response response = new Response();
        response.setResponseStr("response:");

        MyFilterChain chain = new MyFilterChain();
        chain.addFilter(new HTMLFilter()).addFilter(new FaceFilter()).addFilter(new SensitiveFilter());

        chain.doFilter(request, response, chain);

        System.out.println(request.getRequestStr());
        System.out.println(response.getResponseStr());
    }
}

结果:

^V^,[script},,就业,网络授课------来自HTMLFilter----FaceFilter()------来自SensitiveFilter
response:------sensitiveFilter()---FaceFilter()----HTMLFilter()

https://gitee.com/play-happy/base-project

参考:

[1] 博客,http://blog.csdn.net/jason0539/article/details/45091639

[2] 博客,http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html

[3] 博客,http://www.cnblogs.com/ysw-go/p/5432921.html