责任链模式(Chain of Responsibility Pattern)这是一种行为设计模式,通过解耦请求的发送者和接收者,使多个对象有机会处理请求。在这种模式下,请求沿着一个处理链传输,直到一个对象能够处理它。
本文将详细介绍责任链模式的概述、应用场景和代码示例,以帮助读者更好地理解和应用该模式。
1. 简介模式概述责任链模式的核心思想是解耦请求的发送者和接收者,使多个对象有机会处理请求。在责任链模式下,请求将沿着处理链传递,每个处理器都有机会处理请求。如果处理器不能处理请求,请求将传递给下一个处理器,直到处理器能够处理它。
责任链模式包括以下角色:
责任链模式类结构
- 抽象处理者(Handler):对处理请求的界面进行定义,通常包括对下一个处理器的引用,以将请求传递给下一个处理器。
- 具体处理者(ConcreteHandler):如果处理请求的接口已经实现,具体处理者可以决定是否处理请求。如果不能处理,请求将传递给下一个处理器。
- 客户端(Client):创建处理对象并形成责任链的结构,负责将请求发送给第一处理对象。
优点:
- 责任链模式可以解耦要求的发送者和接收者。发送者只需要向第一个处理器发送请求,而不需要关心哪个处理器来处理。这样,系统的灵活性大大提高,处理器的顺序可以随时增加或修改。
- 责任链模式可以避免发送者和接收者之间的紧密耦合。每个处理器只需要关心他负责的请求类型和其他请求。这样,系统的可维护性也得到了提高。
- 责任链模式可以灵活动态地添加或删除处理器。我们可以根据实际情况调整责任链的结构,以满足不同的业务需求。
缺点:
- 如果责任链过长或处理者之间的关系复杂,复杂性会显著提高,这也可能导致性能下降和调试困难。
责任链模式广泛应用于许多不同的应用场景。以下是一些常见的应用场景:
- 请求处理链:当一个请求需要多个处理步骤或处理器时,可以使用责任链模式。每个处理器负责部分逻辑,可以选择将请求传递给下一个处理器,从而形成一个处理链。
- 日志记录:在日志系统中,可以使用责任链模式来记录日志。不同的处理器可以负责不同级别的日志记录。例如,一个处理器负责记录错误的日志,另一个处理器负责记录调试日志,然后根据链结构传输日志。
- 身份验证和权限检查:在身份验证和权限检查系统中,可以使用责任链模式来验证用户的身份和权限。每个处理器都可以检查特定的条件,如用户名和密码的正确性、账户是否锁定等。如果处理器不能通过验证,请求可以传递给下一个处理器。
- 数据过滤和转换:在数据处理过程中,责任链模式可用于数据过滤和转换。每个处理器可以根据特定条件过滤数据或转换数据,然后将处理后的数据传输给下一个处理器。
- 错误处理和异常处理:在错误处理和异常处理系统中,可以使用责任链模式来处理错误和异常。不同的处理器可以处理不同类型的错误或异常,并根据需要将错误或异常传递给下一个处理器进一步处理或记录。
在 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
框架实现责任链模式的高级版本。
在实际开发中,一个请求会在多个处理器之间流通,每个处理器都可以处理请求。
假设我们有一个 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】每周分享技术干货、开源项目、实践经验、高效开发工具等,您的关注将是我更新的动力!