是设计模式,我们有救了!!!(七、责任链模式:Chain of Responsibity)

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式。它的核心思想是​​将多个处理请求的对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止​​。这种模式让请求的发送者不需要知道谁最终会处理它的请求,从而实现发送者和接收者的解耦,并允许多个对象都有机会处理请求

优点​​:

  • ​降低耦合度​:请求发送者无需知道具体由哪个处理者处理请求,处理者也无需知道链的全貌。
  • ​增强灵活性与可扩展性​:可以在运行时动态地添加、移除或修改链中的处理者顺序,符合"开闭原则"。
  • ​简化对象职责​:每个具体处理者只需关注自己职责范围内的请求,符合"单一职责原则"。

​缺点​​:

  • ​请求可能未被处理​:如果链配置不当或没有合适的处理者,请求可能到达链的末端也无法被处理。
  • ​性能考虑​:较长的责任链可能会带来性能开销,因为请求可能需要遍历多个对象。
  • ​调试难度​:请求的传递是隐式的,调试时可能难以跟踪请求的处理路径和确定最终是哪个处理者处理的。

场景模拟:请假。 你是一个公司员工,在你的上方有许多领导,并且你的请假也是需要经过层层审批才能够通过。类图如下:

先关注两个地方: Handler(处理)接口:所有参与审批流程过的对象都必须要实现的就接口,接口中有两个方法。execute:执行是否通过你的请假申请的逻辑。setNextHander:设置自己审批之后的下一个对象是谁。

Handler的实现类:假设在我们的场景中,你的请假需要三个人的通过:1,你的mentor。2,你的leader。3,你们公司的总监Boss。那么这三个对象则都需要实现上述接口。

按照我们的期望来说,肯定是希望mentor审批之后,leader再审批,最后是Boss。如果我们直接硬编码实现会导致三者的执行过程混合在了一起,一旦某一个人的审批逻辑发生了变化就需要在公共的地方进行修改,那么这一部分的代码就会变得十分混乱。责任链的思想则是,让每一个参与流程的审批人能够刚感知到下一个审批人的存在,这样在该对象的内部就可以只考虑自己的审批过程,审批完之后调用下一个审批者的审批方法即可。这样一来每个审批者发生变化时,只需要改自己的代码,有新的审批者加入也很方便。

先来看一下我们的请假条实体类:

kotlin 复制代码
@Data
public class LeaveRequestFormDTO {
    //请假原因
    private String Reason;
    //请假天数
    private Integer days;
}

Handler接口:

csharp 复制代码
public interface Handler {
    void execute(LeaveRequestFormDTO data);
    void setNextHandler(Handler handler);
}

Mentor很好说话

kotlin 复制代码
public class MentorHandler implements Handler{

    private Handler nextHandler;
    @Override
    public void execute(LeaveRequestFormDTO data) {
        System.out.println("Mentor觉得可以,通过你的申请");
        if(this.nextHandler!=null){
            this.nextHandler.execute(data);
        }
    }

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

Leader比较难搞

kotlin 复制代码
public class LeaderHandler implements Handler{
    private Handler nextHandler;
    @Override
    public void execute(LeaveRequestFormDTO data) {
        if(data.getDays() > 20){
            throw new RuntimeException("时间也太久了,不通过");
        }
        System.out.println("Leader觉得可以,通过你的申请");
        if(this.nextHandler!=null){
            this.nextHandler.execute(data);
        }
    }

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

老板简直是出生

kotlin 复制代码
public class BossHandler implements Handler{
    private Handler nextHandler;

    @Override
    public void execute(LeaveRequestFormDTO data) {
        if(!data.getReason().contains("生病")){
            throw new RuntimeException("没生病请什么假?");
        }
        System.out.println("Boss觉得可以,通过你的申请");
        if(this.nextHandler!=null){
            this.nextHandler.execute(data);
        }

    }

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

可以看到每个审批人都是有自己的逻辑的,但是毫无例外的都会在最后调用下一个审批人的审批方法。但是现在我们只是有了三个独立的类,如何将他们组装起来使审批行为变成链路呢?在我这里,BaseHandler并不是一个审批者,他只是用来将所有的审批对象进行组装,然后将第一个审批者回传给客户端的工具。当然也可以直接在客户端进行组装,我只是为了代码清爽,你可以有自己的风格。

csharp 复制代码
public class BaseHandler {
    //短暂的存储一下所有的审批者
    private List<Handler> handlers= new ArrayList<>();

    public List<Handler> getHandlers(){
        return this.handlers;
    }
    //将暂存的所有审批者之间的关系进行链接,形成责任链
    private void init(){
        if(handlers.isEmpty()){
            return;
        }
        for (int i=0; i<handlers.size(); i++){
            Handler handler = handlers.get(i);
            if(i+i <= handlers.size()){
                handler.setNextHandler(handlers.get(i+1));
            }
        }
    }
    //简单工厂方法,创建所有的审批者
    public static Handler build(){
        BaseHandler baseHandler = new BaseHandler();
        List<Handler> list = baseHandler.getHandlers();

        MentorHandler mentorHandler = new MentorHandler();
        LeaderHandler leaderHandler = new LeaderHandler();
        BossHandler bossHandler = new BossHandler();

        list.add(mentorHandler);
        list.add(leaderHandler);
        list.add(bossHandler);
        baseHandler.init();
        return baseHandler.getHandlers().get(0);

    }
}

那么接下来在客户端你就可以开始请假啦:

csharp 复制代码
public class Client {
    public static void main(String[] args) {
        LeaveRequestFormDTO dto = new LeaveRequestFormDTO();
        dto.setDays(20);
        dto.setReason("领导我生病了(实际还是请假的借口罢了)");
        try{
            Handler handler = BaseHandler.build();
            handler.execute(dto);
            System.out.println("恭喜你请假通过!!!");
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.out.println("很遗憾,你的请假审批流程被中断了。。。");
        }
    }
}

执行结果: Mentor觉得可以,通过你的申请 Leader觉得可以,通过你的申请 Boss觉得可以,通过你的申请 恭喜你请假通过!!!

Process finished with exit code 0

相关推荐
码事漫谈4 分钟前
后端开发如何将创新转化为专利?案例、流程与实操指南
后端
小坏讲微服务1 小时前
SpringCloud零基础学全栈,实战企业级项目完整使用
后端·spring·spring cloud
humors2211 小时前
服务端开发案例(不定期更新)
java·数据库·后端·mysql·mybatis·excel
Easonmax4 小时前
用 Rust 打造可复现的 ASCII 艺术渲染器:从像素到字符的完整工程实践
开发语言·后端·rust
百锦再4 小时前
选择Rust的理由:从内存管理到抛弃抽象
android·java·开发语言·后端·python·rust·go
小羊失眠啦.4 小时前
深入解析Rust的所有权系统:告别空指针和数据竞争
开发语言·后端·rust
q***71854 小时前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
大象席地抽烟5 小时前
使用 Ollama 本地模型与 Spring AI Alibaba
后端
程序员小假5 小时前
SQL 语句左连接右连接内连接如何使用,区别是什么?
java·后端
小坏讲微服务5 小时前
Spring Cloud Alibaba Gateway 集成 Redis 限流的完整配置
数据库·redis·分布式·后端·spring cloud·架构·gateway