前言
在 设计模式(四)责任链模式 —— 责任链模式结构 中分析了责任链模式的结构,在日常开发中经常结合spring容器来使用,借助容器的一些特性,同时可以解决一些责任链模式的不足。
场景案例
如以电商系统下单流程为例,简化一下这个流程,只包含库存、价格、优惠券三个业务步骤。
类图结构
在spring中优雅的使用责任链模式
定义业务用到的基础类
定义OrderDTO和ResultDTO
import java.io.Serializable;
/**
* @author lishuzhen
* @createTime 2022年06月19日 22:40:00
*/
public class ResultDTO implements Serializable {
private String msg;
public static ResultDTO ok(){
return new ResultDTO();
}
public ResultDTO() {
msg = "ok";
}
public String getMsg() {
return msg;
}
}
/**
* @author lishuzhen
* @createTime 2022年06月19日 22:15:00
*/
public class OrderDTO {
private String orderNo;
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
}
定义抽象的处理器接口
- 定义doFilter方法,由子类实现处理器的内部逻辑,注意在doFilter方法的最后一步要记得调用doNextFilter()
- 定义doNextFilter方法,由抽象类完成调用下一个处理器的代码。
/**
* 处理器抽象类
*
* @author lishuzhen
* @createTime 2022年06月19日 22:52:00
*/
public abstract class AbstractOrderChainHandler {
private AbstractOrderChainHandler nextHandler;
/**
* 执行过滤方法
*
* @param orderDTO
* @return
*/
abstract protected ResultDTO doFilter(OrderDTO orderDTO);
/**
* 执行下一个处理器
*
* @param orderDTO
* @param resultDTO
* @return
*/
protected ResultDTO doNextHandler(OrderDTO orderDTO, ResultDTO resultDTO) {
if (nextHandler == null) {
return resultDTO;
}
return nextHandler.doFilter(orderDTO);
}
public void setNextHandler(AbstractOrderChainHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
定义处理器的子类实现
- 必须实现抽象的处理器接口,供容器启动时获取所有的处理器实现类
- 通过@Order注解,标识当前处理器在整个责任链中的位置。建议区间设置的大一些,后续增加处理器时比较方便。
/**
* 订单提交-库存计算处理器
*
* @author lishuzhen
* @createTime 2022年06月19日 22:57:00
*/
@Service
@Order(100)
public class StockOrderChainHandler extends AbstractOrderChainHandler {
/**
* 执行过滤方法
*
* @param orderDTO
* @return
*/
@Override
protected ResultDTO doFilter(OrderDTO orderDTO) {
System.out.println("库存计算处理");
return doNextHandler(orderDTO, ResultDTO.ok());
}
}
/**
* 订单提交-价格计算处理器
*
* @author lishuzhen
* @createTime 2022年06月19日 22:59:00
*/
@Service
@Order(300)
public class PriceOrderChainHandler extends AbstractOrderChainHandler {
/**
* 执行过滤方法
*
* @param orderDTO
* @return
*/
@Override
protected ResultDTO doFilter(OrderDTO orderDTO) {
System.out.println("价格计算处理");
return doNextHandler(orderDTO, ResultDTO.ok());
}
}
/**
* 订单提交-优惠券计算处理器
*
* @author lishuzhen
* @createTime 2022年06月19日 22:59:00
*/
@Service
@Order(200)
public class CouponOrderChainHandler extends AbstractOrderChainHandler {
/**
* 执行过滤方法
*
* @param orderDTO
* @return
*/
@Override
protected ResultDTO doFilter(OrderDTO orderDTO) {
System.out.println("优惠券处理");
return doNextHandler(orderDTO, ResultDTO.ok());
}
}
封装组合责任链
- 通过@Autowired修饰责任链(处理器的集合),spring容器会按照@order的顺序组装一个有序的list集合。
- 通过@PostConstruct修饰constructChain()方法,使容器回调此方法,完成为每一个处理设置它的下一个处理器
- 定义firstHandler,表示这是当前责任链路顶端的第一个处理器。
/**
* 订单处理责任链
*
* @author lishuzhen
* @createTime 2022年06月19日 23:05:00
*/
@Service
public class OrderChainHandler {
@Autowired
private List<AbstractOrderChainHandler> chain;
private AbstractOrderChainHandler firstHandler;
@PostConstruct
private void constructChain() {
if (chain == null || chain.size() == 0) {
throw new RuntimeException("not found order chain handler");
}
firstHandler = chain.get(0);
for (int i = 0; i < chain.size(); i++) {
if (i == chain.size() - 1) {
chain.get(i).setNextHandler(null);
} else {
chain.get(i).setNextHandler(chain.get(i + 1));
}
}
}
public ResultDTO executionChain(OrderDTO orderDTO) {
return firstHandler.doFilter(orderDTO);
}
}
写一个测试接口
@Controller
@RequestMapping("/lsz")
public class OrderTestController {
@Autowired
private OrderChainHandler orderChainHandler;
@ResponseBody
@RequestMapping("testOrder")
public Object testOrder(String orderNo){
return orderChainHandler.executionChain(new OrderDTO()).getMsg();
}
}
查看日志
可以看到控制台日志按照责任链处理器的顺序打印了日志
总结
优点
- 降低了各个处理器之间的耦合,各处理器只关注处理自身的内部逻辑,然后抛给下一个处理器即可。
- 不需要关注具体的上下游调用关系,在组装责任链时通过spring的特性动态注入下一个处理器的调用关系。
- 通过@Order注解,可灵活调整各处理器之间的调用顺序
缺点
- 会增加程序的复杂度,需评估酌情使用,不可为了设计模式而用设计模式。