责任链设计模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合。责任链模式通过将这些对象连成一条链,并沿着这条链传递请求,直到某个对象处理它为止。
1. 基础代码示例
/**
* cyt 20240814 根据参数查找运费模板
* @param waybillDTO
* @return 运费模板实体
*/
private CarriageEntity findCarriage(WaybillDTO waybillDTO) {
// 1. 如果是同城
。。。处理逻辑。。。
return carriageEntity;
// 2. 如果是同省
。。。处理逻辑。。。
return carriageEntity;
// 3. 如果是经济区
。。。处理逻辑。。。
return carriageEntity;
// 4. 跨省
。。。处理逻辑。。。
return carriageEntity;
}
在上述的代码中,判断了很多种情况,如果后续要再增加不同类型的模板或者调整模板之间的优先级,就必须改动代码,所以这样的实现扩展性并不好,也不够灵活。这里可以通过【责任链设计模式】来优化。
之所以采用【责任链】模式,是因为在查找模板时,不同的模板处理逻辑不同,并且这些逻辑组成了一条处理链,有开头有结尾,只要能找到符合条件的模板即结束。
2.责任链模式优化代码
2.1 定义处理链抽象类
1. nextHandler:记录下一个处理器
2. setNextHandler:给nextHander赋值
3. doHandler:抽象方法,由具体的处理器实现,用于处理运费模板的查找逻辑
4、doNextHander:已经实现好的,调用下一个处理器的方法
/**
* 运费模板处理链的抽象定义
*/
public abstract class AbstractCarriageChainHandler {
private AbstractCarriageChainHandler nextHandler;
/**
* 执行过滤方法,通过输入参数查找运费模板
*
* @param waybillDTO 输入参数
* @return 运费模板
*/
public abstract CarriageEntity doHandler(WaybillDTO waybillDTO);
/**
* 执行下一个处理器
*
* @param waybillDTO 输入参数
* @param carriageEntity 上个handler处理得到的对象
* @return
*/
protected CarriageEntity doNextHandler(WaybillDTO waybillDTO, CarriageEntity carriageEntity) {
if (nextHandler == null || carriageEntity != null) {
//如果下游Handler为空 或 上个Handler已经找到运费模板就返回
return carriageEntity;
}
return nextHandler.doHandler(waybillDTO);
}
/**
* 设置下游Handler
*
* @param nextHandler 下游Handler
*/
public void setNextHandler(AbstractCarriageChainHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
2.2 实现具体的处理器
定义顺序,继承处理链抽象类,实现doHander抽象方法,在doHander最后返回doNextHander。
2.2.1 同城寄
/**
* 同城寄
*/
@Order(100) //定义顺序
@Component
public class SameCityChainHandler extends AbstractCarriageChainHandler {
@Override
public CarriageEntity doHandler(WaybillDTO waybillDTO) {
。。。处理逻辑。。。
return doNextHandler(waybillDTO, carriageEntity);
}
}
2.2.2 省内寄
/**
* 省内寄
*/
@Order(200) //定义顺序
@Component
public class SameProvinceChainHandler extends AbstractCarriageChainHandler {
@Override
public CarriageEntity doHandler(WaybillDTO waybillDTO) {
。。。处理逻辑。。。
return doNextHandler(waybillDTO, carriageEntity);
}
}
2.2.3 经济区互寄
/**
* 经济区互寄
*/
@Order(300) //定义顺序
@Component
public class EconomicZoneChainHandler extends AbstractCarriageChainHandler {
@Override
public CarriageEntity doHandler(WaybillDTO waybillDTO) {
。。。处理逻辑。。。
return doNextHandler(waybillDTO, carriageEntity);
}
}
2.2.4 跨省寄
/**
* 跨省
*/
@Order(400) //定义顺序
@Component
public class TransProvinceChainHandler extends AbstractCarriageChainHandler {
@Override
public CarriageEntity doHandler(WaybillDTO waybillDTO) {
。。。处理逻辑。。。
return doNextHandler(waybillDTO, carriageEntity);
}
}
2.3 组装处理链
组装处理链,按照@Order
注解中的值,由小到大排序。
/**
* 查找运费模板处理链 @Order注解指定handler顺序
*/
@Component
public class CarriageChainHandler {
/**
* 利用Spring注入特性,按照 @Order 从小到达排序注入到集合中
*/
@Resource
private List<AbstractCarriageChainHandler> chainHandlers;
private AbstractCarriageChainHandler firstHandler;
/**
* 组装处理链
*/
@PostConstruct // Spring自动调用该方法
private void constructChain() {
if (CollUtil.isEmpty(chainHandlers)) {
throw new SLException("not found carriage chain handler!");
}
//处理链中第一个节点
firstHandler = chainHandlers.get(0);
for (int i = 0; i < chainHandlers.size(); i++) {
if (i == chainHandlers.size() - 1) {
//最后一个处理链节点
chainHandlers.get(i).setNextHandler(null);
} else {
//设置下游节点
chainHandlers.get(i).setNextHandler(chainHandlers.get(i + 1));
}
}
}
public CarriageEntity findCarriage(WaybillDTO waybillDTO) {
//从第一个节点开始处理
return firstHandler.doHandler(waybillDTO);
}
}
@PostConstruct
:这个注解标注的方法会在 Spring 完成依赖注入后自动调用,用来初始化责任链。
3. 总结
调用carriageChainHandler.findCarriage(waybillDTO)方法和直接调用基础代码示例中的findCarriage(waybillDTO)方法,效果相同,完成了责任链模式的代码优化。
通过这种设计,如果将来需要新增处理逻辑或调整处理顺序,只需新建处理器类或调整 @Order
注解的值,而无需修改现有的代码结构,极大地提高了代码的可维护性和扩展性。