「设计模式」责任链模式

148 阅读4分钟

一、概述

责任链模式(Chain of Responsibility Pattern)使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

责任链模式很好理解, 比如平时在公司请假,请假小于3天,小组长审批即可;3天到5天,需要小组长和部门领导审批二级审批;大于5天的,需要小组长、部门领导和VP审批三级审批。

责任链模式的2种角色:

抽象处理角色(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继连接。

具体处理者角色(ConcreteHandler):实现抽象处理者的处理方法,该处理方法中会进行判断能够处理本次请求,如果可以则将请求转给其后继者继续执行处理方法。

二、优缺点

优点

1、降低耦合度。它将请求的发送者和接收者解耦。

2、简化了对象。使得对象不需要知道链的结构。

3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

4、增加新的请求处理类很方便。

缺点

1、不能保证请求一定被接收。

2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。

3、可能不容易观察运行时的特征,有碍于除错。

三、实现方式

以上面请假为案例简单实现责任链模式。

抽象处理类

public abstract class Handler {

    //天数阈值
    protected int daysThreshold;


    private Handler nextHandler;

    public void setNextHandler(Handler nextHandler){
        this.nextHandler = nextHandler;
    }

    public void leaveHandler(int days, String msg,int step){
        if(days >= this.daysThreshold){
            pass(msg, step++);
        }

        if(nextHandler != null){
            nextHandler.leaveHandler(days,msg, step);
        }
    }

    abstract void pass(String msg, int step);

}

具体处理类(组长审批)

public class GroupLeaderHandler extends Handler{

    public GroupLeaderHandler(int daysThreshold){
        this.daysThreshold = daysThreshold;
    }
    @Override
    void pass(String msg, int step) {
        System.out.println("("+step+")组长审批:" + msg);
    }
}

具体处理类(部门领导审批)

public class DeptLeaderHandler extends Handler{

    public DeptLeaderHandler(int daysThreshold){
        this.daysThreshold = daysThreshold;
    }
    @Override
    void pass(String msg, int step) {
        System.out.println("("+step+")部门领导审批:" + msg);
    }
}

具体处理类(VP审批)

public class VPHandler extends Handler{

    public VPHandler(int daysThreshold){
        this.daysThreshold = daysThreshold;
    }
    @Override
    void pass(String msg, int step) {
        System.out.println("("+step+")大大领导VP审批:" + msg);
    }
}

客户端

public class Client {

    public static Handler getClient(){
        /**
         * 1、小于3天,需要组长审批
         * 2、3-5天,需要组长、部门领导审批
         * 3、大于5天,需要组长、部门领导、VP审批
         */
        Handler groupLeader = new GroupLeaderHandler(1);//组长审批
        Handler departmentLeader = new DeptLeaderHandler(3);//部门领导审批
        Handler boss = new VPHandler(6);//Vp审批

        groupLeader.setNextHandler(departmentLeader);
        departmentLeader.setNextHandler(boss);

        return groupLeader;
    }
    public static void main(String[] args) {

        Handler client = getClient();

        for(int i=1;i<=10;i++){
            client.leaveHandler(i,"请"+i+"天假",1);
            System.out.println("----------------");
        }
    }
}

结果输出

(1)组长审批:请1天假
----------------
(1)组长审批:请2天假
----------------
(1)组长审批:请3天假
(2)部门领导审批:请3天假
----------------
(1)组长审批:请4天假
(2)部门领导审批:请4天假
----------------
(1)组长审批:请5天假
(2)部门领导审批:请5天假
----------------
(1)组长审批:请6天假
(2)部门领导审批:请6天假
(3)大大领导VP审批:请6天假
----------------
(1)组长审批:请7天假
(2)部门领导审批:请7天假
(3)大大领导VP审批:请7天假
----------------
(1)组长审批:请8天假
(2)部门领导审批:请8天假
(3)大大领导VP审批:请8天假
----------------
(1)组长审批:请9天假
(2)部门领导审批:请9天假
(3)大大领导VP审批:请9天假
----------------
(1)组长审批:请10天假
(2)部门领导审批:请10天假
(3)大大领导VP审批:请10天假

四、常见应用场景

  • Java中,异常机制就是一种责任链模式。一个try可以对应多个catch,当第一个catch不匹配类型,则自动跳到第二个catch;
  • Javascript语言中,事件的冒泡和捕获机制。Java语言中,事件的处理采用观察者模式。
  • Servlet开发中,过滤器的链式处理。
  • Struts2中,拦截器的调用也是典型的责任链模式。