太优雅了,责任链模式在项目中的实战应用
现实生活中铁链,它由一个个铁环首尾相接构成一条完成的链子,如下图所示:
类比到责任链模式中,铁链中的每个节点可以看成责任链模式中的每个对象,然后每个对象负责处理单一的逻辑。将一个请求从链首端发出,沿着链的路径依次传递到每个节点上处理逻辑,直到所有的对象处理完成这个请求为止,这种设计模式称为责任链模式。
1、项目中责任链模式实战
我们使用责任链模式实现对订单中参数的校验,首先校验订单di是否为空,然后校验下单人是否为空,最后检验收获地址是否为空。业务的流程图如下所示:
针对上述的业务,我们使用责任链的模式来实现这个功能,如下是项目的工程结构图:
(1)定义一个责任链的接口
public interface OrderCheckHandler {
/**
* 当前的订单检测实现逻辑
*
*/
void check(OrderCheckParam orderCheckParam);
/**
* 设置下一个检测的实现逻辑
*
*/
OrderCheckHandler setNext(OrderCheckHandler nextOrderCheckHandler);
}
(2)责任链中的公共逻辑的抽取
public abstract class BaseCheckOrderHandler implements OrderCheckHandler {
private OrderCheckHandler nextOrderCheckHandler;
@Override
public void check(OrderCheckParam orderCheckParam) {
this.currentCheck(orderCheckParam);
if(Objects.nonNull(nextOrderCheckHandler)){
nextOrderCheckHandler.check(orderCheckParam);
}
}
/**
* 具体的实现逻辑
*
*/
protected abstract void currentCheck(OrderCheckParam orderCheckParam);
@Override
public OrderCheckHandler setNext(OrderCheckHandler nextOrderCheckHandler) {
this.nextOrderCheckHandler = nextOrderCheckHandler;
return this.nextOrderCheckHandler;
}
}
(3)具体的检验逻辑(继承公共逻辑)
--------------------订单id校验逻辑---------------------------
@Service
public class OrderIdCheckHandler extends BaseCheckOrderHandler {
@Override
protected void currentCheck(OrderCheckParam orderCheckParam) {
if(orderCheckParam.getOrderId() == null){
throw new RuntimeException("订单id为空");
}
}
}
--------------------用户校验逻辑---------------------------
@Service
public class BuyerCheckHandler extends BaseCheckOrderHandler {
@Override
protected void currentCheck(OrderCheckParam orderCheckParam) {
if(orderCheckParam.getBuyer() == null){
throw new RuntimeException("用户不可以为空");
}
}
}
--------------------收货地址的校验逻辑-------------------------
@Service
public class AddressCheckHandler extends BaseCheckOrderHandler {
@Override
protected void currentCheck(OrderCheckParam orderCheckParam) {
if(orderCheckParam.getAddress() == null){
throw new RuntimeException("用户地址不可以为空");
}
}
}
(4)使用spring将业务逻辑串联起来
@Configuration
public class OrderCheckConfig {
@Bean
public BuyerCheckHandler buyerCheckHandler(){
return new BuyerCheckHandler();
}
@Bean
public OrderIdCheckHandler checkOrderIdHandler(){
return new OrderIdCheckHandler();
}
@Bean
public AddressCheckHandler addressCheckHandler(){
return new AddressCheckHandler();
}
//设置责任链得执行链路顺序
@Bean
public OrderCheckHandler orderCheckHandler(){
OrderIdCheckHandler orderIdCheckHandler = this.checkOrderIdHandler();
orderIdCheckHandler.setNext(this.buyerCheckHandler()).setNext(this.addressCheckHandler());
return orderIdCheckHandler;
}
}
(5)service调用责任链的
@Service
public class OrderService {
@Resource
private OrderCheckHandler orderCheckHandler;
public String checkOrderParam(OrderCheckParam param){
orderCheckHandler.check(param);
return "success";
}
}
(6)controller逻辑
@RestController
@RequestMapping("/test")
public class ZeRenLianTestController {
@Resource
private OrderService orderService;
@GetMapping("/checkOrder")
public String checkOrder(){
OrderCheckParam orderCheckParam = new OrderCheckParam();
orderCheckParam.setAddress("123");
orderCheckParam.setOrderId("1235689");
return orderService.checkOrderParam(orderCheckParam);
}
}
测试结果图:
如果现在需要增加一种校验(如增加订单物流的校验),此时我们只需要增加一个业务的实现类,然后在spring的配置将这个业务实现类加入到责任链逻辑上就可以了。
总结:
(1)需要保证责任链的结构清晰、避免创建过长的链,进而提升执行的性能。
(2)每个业务应该具有单一职责,每个对象专注于处理自己的逻辑。
(3)责任链模式使用的典型场景是多个对象处理同一个请求,如OA审批、参数的校验、日志记录器链等等。