03-JAVA设计模式-责任链模式

责任链模式

什么是责任链模式

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,允许你将请求沿着处理者链进行传递。每个处理者均对请求进行某些处理,并可决定是否将请求沿着链传递下去。这种模式给予请求的处理者更加灵活的组织结构。

在Java中实现责任链模式,通常需要定义一个处理者接口,该接口包含一个或多个方法用于处理请求和决定是否传递请求。

然后,创建具体的处理者类,实现这个接口。 每个处理者可以持有对下一个处理者的引用,从而形成处理者链。

  • 优点

    • 降低了耦合度: 责任链模式通过将请求的处理逻辑分散到多个处理对象中,减少了请求发送者与多个请求处理者之间的耦合。请求发送者只需要将请求发送到链的头部,而不需要知道链的具体结构或处理逻辑。
    • 增强了系统的可扩展性: 当需要增加新的处理逻辑时,只需要创建一个新的处理对象并将其添加到链中即可,无需修改现有代码。这使得系统的扩展变得更加容易和灵活。
    • 提高了系统的灵活性: 每个处理对象都可以独立地决定是否处理请求,以及是否将请求传递给下一个处理对象。这种灵活性使得系统可以根据不同的场景和需求进行动态调整。
    • 实现了请求的有序处理: 通过合理地安排处理对象在链中的顺序,可以确保请求按照特定的顺序进行处理。这对于某些需要按照特定顺序执行的操作非常有用。
  • 缺点

    • 可能导致性能问题: 由于请求需要在多个处理对象之间进行传递,因此可能会增加系统的处理时间。特别是在处理链较长或处理逻辑较复杂的情况下,性能问题可能会更加明显。
    • 调试难度较大: 当责任链较长且处理逻辑复杂时,调试可能会变得相对困难。因为请求在多个处理对象之间传递,定位问题的来源可能需要跨越多个类和方法。
    • 可能导致请求丢失: 如果没有正确设置处理对象的下一个引用,或者处理对象在处理请求时出现了异常,可能会导致请求在链中丢失,从而无法得到处理。
    • 可能增加代码的复杂性: 为了实现责任链模式,需要编写多个处理对象的代码,并确保它们之间的正确连接和传递。这可能会增加代码的复杂性,特别是在处理逻辑较为复杂的情况下。

开发中常见场景

  • java中,异常机制就是一种责任链模式
  • Servlet开发中,过滤器的链式处理
  • Struts2中,拦截器的调用也是典型的责任链模式

案例

公司里,请假条的审批流程:

  • 请假天数小于3天,主任审批
  • 请假天数大于3天,小于10天,经理审批
  • 请假天数大于10天,小于30天,总经理审批
  • 请假天数大于30天,提示拒绝

UML

  • 定义请假单,包含请假人,请假天数,请假原因属性
  • 定义一个处理者接口,并提供两个接口:
    • 自己的处理方式
    • 设置下一处理者
  • 定义主任、经理,总经理三个处理者,定义一个属性存储下一处理者引用,自己处理方式接口中,根据需求进行判断处理,否则调用下一处理者进行处理

实现代码

LeaveOrder.java

java 复制代码
// 请假单
public class LeaveOrder {
    // 请假人
    private String name;
    // 请假天数
    private int days;
    // 原因
    private String reason;

    public LeaveOrder(String name, int days, String reason) {
        this.name = name;
        this.days = days;
        this.reason = reason;
    }

    public String getName() {
        return name;
    }

    public int getDays() {
        return days;
    }

    public String getReason() {
        return reason;
    }
}

LeaveHandle.java

java 复制代码
// 定义处理者接口
public interface LeaveHandle {
    // 定义本人处理方式接口
    void handleRequest(LeaveOrder leaveOrder);
    // 定义下一处理者的引用
    void setNextHandle(LeaveHandle leaveHandle);
}

DirectorLeaveHandle.java

java 复制代码
// 主任
public class DirectorLeaveHandle implements LeaveHandle{

    // 定义一个属性 用于持有下一处理者
    private LeaveHandle nextHandler;

    @Override
    public void handleRequest(LeaveOrder leaveOrder) {
        if(leaveOrder != null && leaveOrder.getDays() <= 3 && leaveOrder.getDays() > 0){
            System.out.printf("主任审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());
        }
        else {
            // 通过持有引用 调用下已处理者进行处理
            nextHandler.handleRequest(leaveOrder);
        }
    }

    @Override
    public void setNextHandle(LeaveHandle leaveHandle) {
        this.nextHandler = leaveHandle;
    }
}

ManagerLeaveHandle.java

java 复制代码
// 经理
public class ManagerLeaveHandle implements LeaveHandle{

    // 定义一个属性 用于持有下一处理者
    private LeaveHandle nextHandler;

    @Override
    public void handleRequest(LeaveOrder leaveOrder) {
        if(leaveOrder != null && leaveOrder.getDays() <= 10 && leaveOrder.getDays() > 3){
            System.out.printf("经理审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());
        }
        else {
            // 通过持有引用 调用下已处理者进行处理
            nextHandler.handleRequest(leaveOrder);
        }
    }

    @Override
    public void setNextHandle(LeaveHandle leaveHandle) {
        this.nextHandler = leaveHandle;
    }
}

GeneralManagerLeaveHandle.java

java 复制代码
// 总经理
public class GeneralManagerLeaveHandle implements LeaveHandle{

    // 定义一个属性 用于持有下一处理者
    private LeaveHandle nextHandler;

    @Override
    public void handleRequest(LeaveOrder leaveOrder) {
        if(leaveOrder != null && leaveOrder.getDays() <= 30 && leaveOrder.getDays() > 10){
            System.out.printf("总经理审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());
        }
        else {
            System.out.println("超过30天拒绝请假");
        }
    }

    @Override
    public void setNextHandle(LeaveHandle leaveHandle) {
        this.nextHandler = leaveHandle;
    }
}

TestClient.java

java 复制代码
public class TestClient {
    public static void main(String[] args) {
        // 创建请假单
        LeaveOrder order = new LeaveOrder("张三",15,"回家");
         创建处理人
        // 主任
        DirectorLeaveHandle directorLeaveHandle = new DirectorLeaveHandle();
        // 经理
        ManagerLeaveHandle managerLeaveHandle = new ManagerLeaveHandle();
        // 总经理
        GeneralManagerLeaveHandle generalManagerLeaveHandle = new GeneralManagerLeaveHandle();

        // 设置责任链
        directorLeaveHandle.setNextHandle(managerLeaveHandle);
        directorLeaveHandle.setNextHandle(generalManagerLeaveHandle);

        // 提交请假申请
        directorLeaveHandle.handleRequest(order);
    }
}

执行结果:

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

相关推荐
xlsw_2 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹3 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭4 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫4 小时前
泛型(2)
java
超爱吃士力架4 小时前
邀请逻辑
java·linux·后端
南宫生4 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石4 小时前
12/21java基础
java
李小白664 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp5 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶5 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb