首页 > 图灵资讯 > 技术篇>正文

设计模式之不一样的责任链模式

2023-06-05 09:25:16

责任链模式(Chain of Responsibility Pattern)这是一种行为设计模式,通过解耦请求的发送者和接收者,使多个对象有机会处理请求。在这种模式下,请求沿着一个处理链传输,直到一个对象能够处理它。

本文将详细介绍责任链模式的概述、应用场景和代码示例,以帮助读者更好地理解和应用该模式。

1. 简介模式概述

责任链模式的核心思想是解耦请求的发送者和接收者,使多个对象有机会处理请求。在责任链模式下,请求将沿着处理链传递,每个处理器都有机会处理请求。如果处理器不能处理请求,请求将传递给下一个处理器,直到处理器能够处理它。

责任链模式包括以下角色:

设计模式之不一样的责任链模式_支付宝

责任链模式类结构

  • 抽象处理者(Handler):对处理请求的界面进行定义,通常包括对下一个处理器的引用,以将请求传递给下一个处理器。
  • 具体处理者(ConcreteHandler):如果处理请求的接口已经实现,具体处理者可以决定是否处理请求。如果不能处理,请求将传递给下一个处理器。
  • 客户端(Client):创建处理对象并形成责任链的结构,负责将请求发送给第一处理对象。
优点与缺点

优点:

  • 责任链模式可以解耦要求的发送者和接收者。发送者只需要向第一个处理器发送请求,而不需要关心哪个处理器来处理。这样,系统的灵活性大大提高,处理器的顺序可以随时增加或修改。
  • 责任链模式可以避免发送者和接收者之间的紧密耦合。每个处理器只需要关心他负责的请求类型和其他请求。这样,系统的可维护性也得到了提高。
  • 责任链模式可以灵活动态地添加或删除处理器。我们可以根据实际情况调整责任链的结构,以满足不同的业务需求。

缺点:

  • 如果责任链过长或处理者之间的关系复杂,复杂性会显著提高,这也可能导致性能下降和调试困难。
应用场景

责任链模式广泛应用于许多不同的应用场景。以下是一些常见的应用场景:

  • 请求处理链:当一个请求需要多个处理步骤或处理器时,可以使用责任链模式。每个处理器负责部分逻辑,可以选择将请求传递给下一个处理器,从而形成一个处理链。
  • 日志记录:在日志系统中,可以使用责任链模式来记录日志。不同的处理器可以负责不同级别的日志记录。例如,一个处理器负责记录错误的日志,另一个处理器负责记录调试日志,然后根据链结构传输日志。
  • 身份验证和权限检查:在身份验证和权限检查系统中,可以使用责任链模式来验证用户的身份和权限。每个处理器都可以检查特定的条件,如用户名和密码的正确性、账户是否锁定等。如果处理器不能通过验证,请求可以传递给下一个处理器。
  • 数据过滤和转换:在数据处理过程中,责任链模式可用于数据过滤和转换。每个处理器可以根据特定条件过滤数据或转换数据,然后将处理后的数据传输给下一个处理器。
  • 错误处理和异常处理:在错误处理和异常处理系统中,可以使用责任链模式来处理错误和异常。不同的处理器可以处理不同类型的错误或异常,并根据需要将错误或异常传递给下一个处理器进一步处理或记录。
2. Java 代码示例

Java 实现责任链模式的方式有很多,包括基于接口、抽象类、基于注释等。以下是基于接口的常见实现方法。

基于接口的实现方法是定义处理请求的接口,每个处理器实现接口,并决定是否处理请求并将请求传递给下一个处理器。

首先,我们定义了处理请求的界面 Handler 请求入参 Request

public interface Handler {    void handleRequest(Request request);}public class Request {    private String type;    // 省略getter、setter}

然后,我们创建了三个特定的处理器来实现这个接口。在实现特定处理器时,我们首先判断我们是否能处理请求。如果可以,我们将处理它们;否则,请求将传递给下一个处理器。代码如下:

public class ConcreteHandlerA implements Handler {    private Handler successor;    public void setSuccessor(Handler successor) {        this.successor = successor;    }    public void handleRequest(Request request) {        if (request.getType().equals("A")) {            // 处理请求的逻辑        } else if (successor != null) {            successor.handleRequest(request);        }    }}public class ConcreteHandlerB implements Handler {    private Handler successor;    public void setSuccessor(Handler successor) {        this.successor = successor;    }    public void handleRequest(Request request) {        if (request.getType().equals("B")) {            // 处理请求的逻辑        } else if (successor != null) {            successor.handleRequest(request);        }    }}public class ConcreteHandlerC implements Handler {    private Handler successor;    public void setSuccessor(Handler successor) {        this.successor = successor;    }    public void handleRequest(Request request) {        if (request.getType().equals("C")) {            // 处理请求的逻辑        } else if (successor != null) {            successor.handleRequest(request);        }    }}

接下来,我们将创建客户端类别 Client,创建处理对象并形成责任链的结构:

public class Client {    public static void main(String[] args) {        Handler handlerA = new ConcreteHandlerA();        Handler handlerB = new ConcreteHandlerB();        Handler handlerC = new ConcreteHandlerC();        handlerA.setSuccessor(handlerB);        handlerB.setSuccessor(handlerC);        // 创建请求并发送给第一个处理器        Request request = new Request("A");        handlerA.handleRequest(request);    }}

在客户端类别中,我们创建了特定的处理对象,并通过 setSuccessor() 该方法构成了责任链的结构。然后,创建请求对象,并将请求发送给第一个处理器。

基于接口的实现简单直观,每个处理器只需要实现一个接口。但其缺点是,如果责任链较长,则需要创建多个处理对象,以增加系统的复杂性和资源消耗。以下是基于 Spring 框架实现责任链模式的高级版本。

3. Spring 代码示例

在实际开发中,一个请求会在多个处理器之间流通,每个处理器都可以处理请求。

假设我们有一个 Spring 框架开发的订单处理系统需要依次进行订单检查、库存处理和付款处理。如果订单不能在处理链接中处理,处理将终止并返回错误信息。只有当每个处理器完成请求处理时,该订单算法才能成功下单。

首先,我们定义订单类 Order

@Data@AllArgsConstructorpublic class orderNo {    private String orderNumber;    private String paymentMethod;    private boolean stockAvailability;    private String shippingAddress;}

然后我们定义了一个抽象订单处理器 OrderHandler

public abstract class OrderHandler {    public abstract void handleOrder(Order order);}

接下来,我们将创建具体的订单处理器,继承抽象订单处理器,实现相应的方法并注册 Spring 中,

@Componentpublic class CheckOrderHandler extends OrderHandler {    public void handleOrder(Order order) {        if (StringUtils.isBlank(order.getOrderNo())) {            throw new RuntimeException(“订单号不能为空”;        }        if (order.getPrice().compareTo(BigDecimal.ONE) <= 0) {            throw new RuntimeException(“订单金额不得小于等于0”;        }        if (StringUtils.isBlank(order.getShippingAddress())) {            throw new RuntimeException(“收货地址不能为空”;        }        System.out.println(通过“订单参数检验”;    }}@Componentpublic class StockHandler extends OrderHandler {    public void handleOrder(Order order) {        if (!order.isStockAvailability()) {            throw new RuntimeException(“订单库存不足”);        }        System.out.println(“库存扣减成功”);    }}@Componentpublic class AliPaymentHandler extends OrderHandler {    public void handleOrder(Order order) {        if (!order.getPaymentMethod().equals(支付宝) {            throw new RuntimeException(“不支持支付宝以外的支付方式”);        }        System.out.println(支付宝预订成功”);    }}

在实现具体订单处理人类时,CheckOrderHandler 负责检查订单参数,StockHandler 负责库存扣减,AliPaymentHandler 负责预订,每个处理者的逻辑是相互独立,不干扰。


最后,我们创建了订单生产链 BuildOrderChain ,链条处理结构用于形成责任链:

@Componentpublic class BuildOrderChain {    @Autowired    private AliPaymentHandler aliPaymentHandler;    @Autowired    private CheckOrderHandler checkOrderHandler;    @Autowired    private StockHandler stockHandler;    List<OrderHandler> list = new ArrayList<>();    @PostConstruct    public void init() {        // 1. 检查订单参数        list.add(checkOrderHandler);        // 2. 扣减库存        list.add(stockHandler);        // 3. 支付宝预订订单        list.add(aliPaymentHandler);    }    public void doFilter(Order order) {        for (OrderHandler orderHandler : this.list) {            orderHandler.handleOrder(order);        }    }}

订单生产链 BuildOrderChain 在类中,我们通过 @PostConstruct 注解下的 init() 一种初始化的方法,将具体的订单处理器按代码顺序形成责任链结构。然后通过 doFilter(order) 处理者依次集合处理方法遍历。

运行代码:

@Slf4j@SpringBootTest@RunWith(SpringRunner.class)public class OrderChainTest {    @Autowired    private BuildOrderChain buildOrderChain;    @Test    public void test() {        Order order = new Order("123456", “支付宝”,                      true, "长沙", new BigDecimal("100"));        buildOrderChain.doFilter(order);    }}-------------------------------订单参数检验通过库存扣减成功,支付宝预订成功

可以看出,订单是通过验证处理器、库存处理器和支付处理器依次处理的,直到整个订单最终完成。


例如,如果我们的订单是针对虚拟无限库存商品的,我们不需要扣除库存,那么我们可以直接建立新的 VirtualGoodsOrderChain 虚拟商品订单生产链类,代码如下,

@Componentpublic class VirtualGoodsOrderChain {    @Autowired    private AliPaymentHandler aliPaymentHandler;    @Autowired    private CheckOrderHandler checkOrderHandler;    List<OrderHandler> list = new ArrayList<>();    @PostConstruct    public void init() {        // 1. 检查订单参数        list.add(checkOrderHandler);        // 2 支付宝预订订单        list.add(aliPaymentHandler);    }    public void doFilter(Order order) {        for (OrderHandler orderHandler : this.list) {            orderHandler.handleOrder(order);        }    }}

运行代码:

@Testpublic void virtualOrderTest() {    Order order = new Order("123456", “支付宝”, true, "长沙", new BigDecimal("100"));    virtualGoodsOrderChain.doFilter(order);}-------------------------------------------订单参数检验通过支付宝成功下订单

4. 总结

一般来说,责任链模式适用于具有独立逻辑或条件、需要灵活组合和扩展的多个处理步骤、每个处理步骤的场景。复杂的处理逻辑可以通过责任链模式分为多个独立的处理步骤,处理步骤的顺序可以动态地组合和调整,从而提高系统的灵活性和可维护性。希望本文能帮助读者理解和应用责任链模式,提高软件设计和开发能力。

关注公众号【waynblog】每周分享技术干货、开源项目、实践经验、高效开发工具等,您的关注将是我更新的动力!

上一篇 JAVA语言错误集锦
下一篇 #yyds干货盘点# LeetCode程序员面试金典:位1的个数

文章素材均来源于网络,如有侵权,请联系管理员删除。