重学设计模式-责任链模式

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它通过将请求沿着链传递,使多个对象都有机会处理该请求,从而避免了请求的发送者与接收者之间的耦合关系。本文将详细介绍责任链模式的定义、优缺点、应用场景,并通过Java代码展示其实现过程。

一、责任链模式的定义

责任链模式又称为职责链模式,其核心思想是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链。当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。在这种模式下,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,因此责任链将请求的发送者和请求的处理者解耦了。

责任链模式属于对象行为型模式,它主要由以下几个角色组成:

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

具体处理者(Concrete Handler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。

客户类(Client):创建处理链,并向链头的具体处理者对象提交请求,无需关心处理细节和请求的传递过程。

二、责任链模式的优缺点

优点

降低了对象之间的耦合度:该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。

增强了系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则。

增强了给对象指派职责的灵活性:当工作流程发生变化时,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。

责任链简化了对象之间的连接:每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if-else 语句。

责任分担:每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

缺点

不能保证每个请求一定被处理:由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。

对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响:遍历多个处理者会影响性能,特别是在一些递归调用中。

责任链建立的合理性要靠客户端来保证,增加了客户端的复杂性:可能会由于责任链的错误设置而导致系统出错,如可能会造成循环调用。
三、责任链模式的应用场景

先介绍一下作者实习时用到的,抽奖需要有规则配置,抽奖前和抽奖后都需要进行规则判断,抽奖中规则采用决策树与本文无关不多做赘述,抽奖前首先要判断是否已登录,再判断是否为黑名单,再判断抽奖次数是否达到抽该奖品的要求,等等一系列判断,只要有一个判断失败就返回,这种情况用责任链模式就非常方便,且对后面的增删查改更加友好

责任链模式在多个场景中都有广泛应用,包括但不限于:

公司事务等级制度:一切关于工程的事务必须根据事务重要等级匹配相应职位的人员处理,如果事务重要等级超过该职位设定的处理范围就需要向上级报告,交由上级处理。

Java过滤器:如Netty中的Pipeline和ChannelHandler,Spring Security,Spring AOP,Dubbo Filter过滤器链等。

ERP系统流程审批:如总经理、人事经理、项目经理的审批流程。

权限控制:在网关作为微服务程序的入口,拦截客户端所有的请求实现权限控制,如先判断Api接口限流、黑名单、用户会话、参数过滤等。

四、Java实现责任链模式

下面是一个详细的Java代码示例,展示了如何实现责任链模式。

  1. 定义请求类
    首先,我们需要定义一个请求类,这个请求类包含了我们想要处理的信息。

java代码示例

java 复制代码
public class Request {
    private String message;
 
    public Request(String message) {
        this.message = message;
    }
 
    public String getMessage() {
        return message;
    }
}
  1. 定义处理器接口
    接下来,我们定义一个处理器接口,它将规定处理请求的方法。

java代码示例

java 复制代码
public interface Handler {
    void setNext(Handler handler); // 设置下一个处理者
    void handle(Request request); // 处理请求的方法
}
  1. 实现具体的处理者类
    我们将实现一个或多个具体的处理者类,这些类将实现Handler接口。

java代码示例

java 复制代码
// 处理者类 A
public class ConcreteHandlerA implements Handler {
    private Handler nextHandler;
 
    @Override
    public void setNext(Handler handler) {
        this.nextHandler = handler;
    }
 
    @Override
    public void handle(Request request) {
        if (request.getMessage().equals("A")) {
            System.out.println("Handler A processed request: " + request.getMessage());
        } else if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }
}
 
// 处理者类 B
public class ConcreteHandlerB implements Handler {
    private Handler nextHandler;
 
    @Override
    public void setNext(Handler handler) {
        this.nextHandler = handler;
    }
 
    @Override
    public void handle(Request request) {
        if (request.getMessage().equals("B")) {
            System.out.println("Handler B processed request: " + request.getMessage());
        } else if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }
}
 
// 处理者类 C
public class ConcreteHandlerC implements Handler {
    private Handler nextHandler;
 
    @Override
    public void setNext(Handler handler) {
        this.nextHandler = handler;
    }
 
    @Override
    public void handle(Request request) {
        if (request.getMessage().equals("C")) {
            System.out.println("Handler C processed request: " + request.getMessage());
        } else if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }
}
4. 组装责任链并测试
最后,我们需要创建一个类来组合所有处理器,形成一个责任链,并通过调用handle方法测试不同的请求。

java
public class ChainOfResponsibility {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        Handler handlerC = new ConcreteHandlerC();
 
        // 设置责任链
        handlerA.setNext(handlerB);
        handlerB.setNext(handlerC);
 
        // 测试请求
        Request requestA = new Request("A");
        Request requestB = new Request("B");
        Request requestC = new Request("C");
        Request requestD = new Request("D");
 
        // 处理请求
        handlerA.handle(requestA); // Handler A processed request: A
        handlerA.handle(requestB); // Handler B processed request: B
        handlerA.handle(requestC); // Handler C processed request: C
        handlerA.handle(requestD); // 无任何处理
    }
}

运行上述代码,你将看到每个请求按照设置的责任链被处理。对应于请求"A"、"B"和"C"的处理结果将被打印出来,而请求"D"则未被处理。

五、责任链模式的变种与扩展

除了上述基本实现外,责任链模式还可以进行变种和扩展,以适应不同的应用场景。

  1. 带有返回值的责任链
    在实际应用中,有时我们希望责任链中的处理者能够返回处理结果。这可以通过修改Handler接口和处理者类的实现来实现。

java代码示例

java 复制代码
// 带有返回值的请求处理接口
public interface Handler<T> {
    void setNext(Handler<T> handler);
    T handle(Request request);
}
 
// 具体的处理者类A,带有返回值
public class ConcreteHandlerA implements Handler<String> {
    private Handler<String> nextHandler;
 
    @Override
    public void setNext(Handler<String> handler) {
        this.nextHandler = handler;
    }
 
    @Override
    public String handle(Request request) {
        if (request.getMessage().equals("A")) {
            return "Handler A processed request: " + request.getMessage();
        } else if (nextHandler != null) {
            return nextHandler.handle(request);
        }
        return null;
    }
}
 
// 具体的处理者类B,带有返回值
public class ConcreteHandlerB implements Handler<String> {
    private Handler<String> nextHandler;
 
    @Override
    public void setNext(Handler<String> handler) {
        this.nextHandler = handler;
    }
 
    @Override
    public String handle(Request request) {
        if (request.getMessage().equals("B")) {
            return "Handler B processed request: " + request.getMessage();
        } else if (nextHandler != null) {
            return nextHandler.handle(request);
        }
        return null;
    }
}
 
// 具体的处理者类C,带有返回值
public class ConcreteHandlerC implements Handler<String> {
    private Handler<String> nextHandler;
 
    @Override
    public void setNext(Handler<String> handler) {
        this.nextHandler = handler;
    }
 
    @Override
    public String handle(Request request) {
        if (request.getMessage().equals("C")) {
            return "Handler C processed request: " + request.getMessage();
        } else if (nextHandler != null) {
            return nextHandler.handle(request);
        }
        return null;
    }
}
 
// 请求类,包含需要被处理的信息
public class Request {
    private String message;
 
    public Request(String message) {
        this.message = message;
    }
 
    public String getMessage() {
        return message;
    }
 
    public void setMessage(String message) {
        this.message = message;
    }
}
 
// 客户端代码,用于测试责任链模式
public class Client {
    public static void main(String[] args) {
        // 创建处理者实例
        Handler<String> handlerA = new ConcreteHandlerA();
        Handler<String> handlerB = new ConcreteHandlerB();
        Handler<String> handlerC = new ConcreteHandlerC();
 
        // 设置责任链
        handlerA.setNext(handlerB);
        handlerB.setNext(handlerC);
 
        // 创建请求
        Request request1 = new Request("A");
        Request request2 = new Request("B");
        Request request3 = new Request("C");
        Request request4 = new Request("D"); // 未知请求,测试链的末尾处理
 
        // 处理请求并打印结果
        System.out.println(handlerA.handle(request1)); // 输出: Handler A processed request: A
        System.out.println(handlerA.handle(request2)); // 输出: Handler B processed request: B
        System.out.println(handlerA.handle(request3)); // 输出: Handler C processed request: C
        System.out.println(handlerA.handle(request4)); // 输出: null(没有处理者处理这个请求)
    }
}
相关推荐
信徒_3 分钟前
Java 内存模型(Java Memory Model, JMM)
java·开发语言·junit
直裾15 分钟前
scala概念
java·开发语言
叶子2024221 小时前
labelme下载
java·jvm·算法
V+zmm101341 小时前
基于微信小程序的快递管理平台的设计与实现ssm+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
小七蒙恩1 小时前
java下载文件流,不生成中间文件。
java·开发语言·状态模式
计算机萍萍学姐2 小时前
ArrayList和LinkedList的区别是什么?
java·数据结构·算法
李老头探索2 小时前
Java List 集合详解:基础用法、常见实现类与高频面试题解析
java·list
黑风风2 小时前
使用 `@Async` 实现 Spring Boot 异步编程
java·spring boot·后端
等一场春雨2 小时前
Spring Boot 3 文件下载、多文件下载以及大文件分片下载、文件流处理、批量操作 和 分片技术
java·spring boot·后端
码喽不秃头2 小时前
java中的特殊文件
java·开发语言