趣谈设计模式——责任链模式

定义:

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

理解:

  让我们去试着理解这一段话,责任链模式,会将一组对象组合成一个链式结构,一个请求,会在这个对象链上被传递和处理,而客户端却不需要知道请求是如何被处理、被哪个对象处理的。
  处理请求的这个动作,对于客户端来说是封装起来的,所以这部分逻辑的修改是不会影响到客户端的。而链式结构,相对来说比较灵活,便于修改结构。
接下来我们来看一个实际生活中的例子:
  假如你们公司的架构是:开发、组长、总监、经理。现在让你去设计一个请假功能,规定3天以内,组长审批,超过3天,不足5天,总监审批。超过5天,经理审批。
经过需求分析,你很容易就设计出了这样的代码:
/**
 * 申请.
 *
 * @author jialin.li
 * @date 2019-12-23 17:34
 */
public class Request {
    /**
     * 申请的天数、申请者
     */
    private Integer days;
    private String applicant;

    //... 省略其他信息


    public Request(Integer days, String applicant) {
        this.days = days;
        this.applicant = applicant;
    }

    public Integer getDays() {
        return days;
    }

    public String getApplicant() {
        return applicant;
    }
}
/**
 * 管理者.
 *
 * @author jialin.li
 * @date 2019-12-23 17:36
 */
public class Manager {
    /**
     * 职位
     */
    private String position;
    //... 省略其他信息


    public Manager(String position) {
        this.position = position;
    }

    public boolean handler(Request request) {
        Integer days = request.getDays();

        switch (this.position) {
            case "组长":
                if (days < 3) {
                    System.out.println("组长已审批");
                    return true;
                } else {
                    System.out.println("组长无权审批");
                    return false;
                }
            case "总监":
                if (days < 5) {
                    System.out.println("总监已审批");
                    return true;
                } else {
                    System.out.println("组长无权审批");
                    return false;
                }
            case "经理":
                System.out.println("经理已审批");
                return true;
            default:
                return true;
        }
    }
}
/**
 * 测试.
 *
 * @author jialin.li
 * @date 2019-12-23 17:47
 */
public class Main {
    public static void main(String[] args) {
        Request xiaozhang = new Request(2, "小张");
        Request xiaoli = new Request(8, "小李");
        Manager teamLeader = new Manager("组长");
        Manager director = new Manager("总监");
        Manager manager = new Manager("经理");

        System.out.println(xiaozhang.getApplicant());
        handler(xiaozhang, teamLeader, director, manager);
        System.out.println(xiaoli.getApplicant());
        handler(xiaoli, teamLeader, director, manager);
    }

    private static void handler(Request request, Manager teamLeader, Manager director, Manager manager) {
        boolean isOK = teamLeader.handler(request);
        if (!isOK) {
            isOK = director.handler(request);
        }
        if (!isOK) {
            manager.handler(request);
        }
    }
}

测试结果:

小张
组长已审批
小李
组长无权审批
组长无权审批
经理已审批

这样做有什么问题?

  首先这种代码非常的僵硬,如果组织架构调整,那么我们既要修改客户端代码也要修改服务端代码。其次这种代码不符合单一职责原则,一个Manager类,承担了组长、总监、经理三个对象的三个处理逻辑,可读性很差。然后是他也不依赖倒置原则,客户端直接和服务端代码耦合在了一起。最后是每次修改组织架构,都要去修改已经写好的代码逻辑,不符合开闭原则。

那么有没有办法可以解决这个问题呢?

  这就要用到我们今天学习的责任链模式了,其实大多数的设计模式,都是为了让代码符合设计原则,而设计原则,又是对面向对象的封装、继承、多态的合理运用。
我们来看一下责任链模式的结构图:

  Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链。
  ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。

重构代码:

学习了责任链模式后,我们利用责任链模式重构我们的请假代码:
/**
 * 管理者.
 *
 * @author jialin.li
 * @date 2019-12-23 18:17
 */
public abstract class AbstractManager {
     AbstractManager superior;

    void setSuperior(AbstractManager manager) {
        this.superior = manager;
    }

    abstract void requestApplications(Request request);
}
/**
 * 申请.
 *
 * @author jialin.li
 * @date 2019-12-23 17:34
 */
public class Request {
    /**
     * 申请的天数、申请者
     */
    private Integer days;
    private String applicant;

    //... 省略其他信息


    public Request(Integer days, String applicant) {
        this.days = days;
        this.applicant = applicant;
    }

    public Integer getDays() {
        return days;
    }

    public String getApplicant() {
        return applicant;
    }
}
/**
 * 组长.
 *
 * @author jialin.li
 * @date 2019-12-23 18:20
 */
public class TeamLeader extends AbstractManager {

    @Override
    void requestApplications(Request request) {
        Integer days = request.getDays();
        if (days < 3) {
            System.out.println("组长已审批");
        } else {
            System.out.println("组长无权审批");
            superior.requestApplications(request);
        }
    }
}
/**
 * 总监.
 *
 * @author jialin.li
 * @date 2019-12-23 18:23
 */
public class Director extends AbstractManager {
    @Override
    void requestApplications(Request request) {
        Integer days = request.getDays();
        if (days < 5) {
            System.out.println("经理已审批");
        } else {
            System.out.println("经理无权审批");
            superior.requestApplications(request);
        }
    }
}
/**
 * 经理.
 *
 * @author jialin.li
 * @date 2019-12-23 18:24
 */
public class Manager extends AbstractManager {

    @Override
    void requestApplications(Request request) {
        Integer days = request.getDays();

        System.out.println("经理已审批");
    }
}
/**
 * 测试.
 *
 * @author jialin.li
 * @date 2019-12-23 18:25
 */
public class Main {
    public static void main(String[] args) {
        // 构建责任链
        TeamLeader teamLeader = new TeamLeader();
        Director director = new Director();
        Manager manager = new Manager();
        teamLeader.setSuperior(director);
        director.setSuperior(manager);

        Request xiaozhang = new Request(2, "小张");
        Request xiaoli = new Request(8, "小李");

        teamLeader.requestApplications(xiaozhang);
        teamLeader.requestApplications(xiaoli);
    }
}

结果

组长已审批
组长无权审批
经理无权审批
经理已审批
  可以看出,这样的设计非常的灵活,如果组织架构需要调整,只需要新创建一个类,改变责任链的结构即可,不用对服务端的代码进行修改,只需要扩展即可,每个类负责一个职位,符合单一原则职责,代码也较为简洁。

Tomcat中责任链的使用

  Tomcat中的过滤器是一个链式结构,不同的过滤器可以组成一个过滤器链。
Tomcat中的容器也使用的责任链模式,Tomcat中有4种容器(engine、host、context、wrapper),容器间为父子关系,由组织模式将他们组成一个树形结构,每个容器都有其处理请求的逻辑,而请求在容器内部的传递,用的正式责任链模式,每一个value是一个处理节点,invoke是处理方法,第一个处理节点是由Adapter调用:

猜你喜欢

转载自www.cnblogs.com/nedulee/p/12087972.html