设计模式-总览https://mp.csdn.net/mp_blog/creation/editor/122202507 最近对项目上的部分代码进行了重构,使用了责任链模式(链条的创建本身使用了建造者模式)使代码结构更加整洁和清晰。
1、项目背景
当前订单相关的分页查询,对应多个前端(项目没有使用BFF进行搭建)写了不同的API接口,而每个分页订单接口对于返回的订单实体字段稍微有些不同。即除了订单表的字段外还需要额外查询其他微服务系统中的字段,比如:门店名称、会员信息等。大致的处理过程都是先根据查询的分页订单信息,使用lamda将订单表的storeId字段进行聚合去重,再调用门店系统的批量查询接口,最好将门店相关字段回填到订单分页数据中。
当前端1接口需要添加:字段1、字段2、字段3;前端2接口需要填充:字段1、字段3、字段4,这样的化整个内部方法就比较臃肿比较乱。即使具体查询字段1、字段2都是方法级别(可以复用、原子性)但是每个字段维度的lamda获取非重复的门店id集合,回填字段等总体看上去还是比较乱,整体方法的长度就与需要填充字段的个数成正增长。所以这里将其抽成责任链,当后续需要增加额外的字段时,只需要增加链条的实现,并且在需要的调用添加链条即可。
2、重构后代码
1)、定义责任链的链条接口,内部订单Builder模式创建责任链
/**
* 字段填充处理器
* @author kevin
* @date 2011/11/16 9:25
* @since 1.1.2
*/
public abstract class FieldHandler {
/** 下一个调用链 */
protected FieldHandler nextHandle;
public void setNextHandle(FieldHandler nextHandle) {
this.nextHandle = nextHandle;
}
public void handle(List<OrderSourceEntity> sourceList, List<OrderTargetDTO> wrapList) {
if (CollectionUtils.isEmpty(sourceList)) {
return;
}
// 处理当前链条的业务
this.additionField(sourceList, wrapList);
// 如果还有下一个链条,执行下一个链条的业务, 这样整个链条就执行递归起来了,直到链条的最后一节
if (nextHandle != null) {
this.nextHandle.handle(sourceList, wrapList);
}
}
/**
* 填充字段动作
* @param sourceSortList 原始数据
* @param wrapList 填充数据
*/
protected abstract void additionField(List<OrderSourceEntity> sourceList, List<OrderTargetDTO> wrapList);
public static class Builder {
private FieldHandler head;
private FieldHandler tail;
public Builder addHandler(FieldHandler fieldHandler) {
if (this.head == null) {
this.head = this.tail = fieldHandler;
return this;
}
//头部已有元素,从尾部开始追加 添加下一个元素
this.tail.setNextHandle(fieldHandler);
// 指针位置移动一位,同时head也指向下一个
this.tail = fieldHandler;
return this;
}
public FieldHandler build() {
return this.head;
}
}
}
2)、根据责任链接口,定义每个链条的实现,比如当前为门店字段填充的实现
/**
* 门店字段填充处理器
* @author kevin
* @date 2011/11/16 9:57
* @since 1.1.2
*/
@Service
@AllArgsConstructor
public class StoreFieldHandler extends FieldHandler {
private final RemoteStoreAdaptService remoteStoreAdaptService;
@Override
protected void additionField(List<OrderSourceEntity> sourceList, List<OrderTargetDTO> wrapList) {
// 获取列表门店编号集合
List<String> storeCodes = sourceList.stream().map(OrderSourceEntity::getStoreCode).distinct().collect(Collectors.toList());
// rpc(feign或者dubbo)查询门店系统的门店名称
Map<String, String> storeMap = remoteStoreAdaptService.getStoreNameCodeMapping(storeCodes);
// 合并门店详情信息
wrapList.forEach(sort -> sort.setStoreName(storeMap.get(sort.getStoreCode())));
}
}
3)、责任链的组装和调用
像很多复杂责任链一样,都会有Pipeline的容器管道,即可能是动态创建责任链并且进行链条的调用。这里业务比较简单,整个链条是固定的。使用了一个容器来供外部调用固定链条,也允许调用者传入链条的组成方式。
@Service
public class AdditionChainContext implements BeanFactoryAware, InitializingBean {
protected static BeanFactory beanFactory;
// 订单门店商家的责任链
private static FieldHandler orderStoreMerchantPipeline;
// 订单门店会员的责任链
private static FieldHandler orderStoreMemberPipeline;
/** 由于某一个链条需要上一个链条的数据,这里放到了ThreadLocal中,到了某个链条直接可以拿数据用*/
public static final ThreadLocal<List<OrderInfo>> ORDER_CONTEXT = ThreadLocal.withInitial(() -> null);
@Override
public void setBeanFactory(@Nullable BeanFactory beanFactory) throws BeansException {
AdditionChainContext.beanFactory = beanFactory;
}
@Override
public void afterPropertiesSet() {
OrderFieldHandler orderFieldHandler = beanFactory.getBean(OrderFieldHandler.class);
StoreFieldHandler storeFieldHandler = beanFactory.getBean(StoreFieldHandler.class);
MerchantFieldHandler merchantFieldHandler = beanFactory.getBean(MerchantFieldHandler.class);
MemberFieldHandler memberFieldHandler = beanFactory.getBean(MemberFieldHandler.class);
// 使用构建器,创建订单门店商家的责任链
orderStoreMerchantPipeline = new FieldHandler.Builder()
.addHandler(orderFieldHandler)
.addHandler(storeFieldHandler)
.addHandler(merchantFieldHandler).build();
// 使用构建器,订单门店会员的责任链
orderStoreMemberPipeline = new FieldHandler.Builder()
.addHandler(orderFieldHandler)
.addHandler(storeFieldHandler)
.addHandler(memberFieldHandler).build();
}
/**
* 自定义调用链路
* @param sourceSortList 原始订单数据
* @param wrapList 填充数据
* @param classes 责任链类
*/
@SafeVarargs
public static void listChain(List<OrderSourceEntity> sourceList, List<OrderTargetDTO> wrapList, Class<? extends FieldHandler> ... classes) {
try {
FieldHandler.Builder builder = new FieldHandler.Builder();
Arrays.stream(classes).forEach(handler -> builder.addHandler(beanFactory.getBean(handler)));
builder.build().handle(sourceList, wrapList);
} finally {
ORDER_CONTEXT.remove();
}
}
/**
* 订单、门店、商家 管道数据填充
* @param sourceSortList 原始订单数据
* @param wrapList 填充数据
*/
public static void orderStoreMerchantChain(List<OrderSourceEntity> sourceList, List<OrderTargetDTO> wrapList) {
try {
orderStoreMerchantPipeline.handle(sourceList, wrapList);
} finally {
ORDER_CONTEXT.remove();
}
}
/**
* 订单、门店、会员 管道数据填充
* @param sourceSortList 原始订单数据
* @param wrapList 填充数据
*/
public static void orderStoreMemberChain(List<OrderSourceEntity> sourceList, List<OrderTargetDTO> wrapList) {
try {
orderStoreMemberPipeline.handle(sourceList, wrapList);
} finally {
ORDER_CONTEXT.remove();
}
}
}
4)、调用责任链
一种是直接调用Spring afterPropertiesSet预先创建好的责任链,如下:
// 填充责任链数据
AdditionChainContext.orderStoreMerchantChain(orderSourceList, orderTargetList);
一种是调用随机传入的责任链:
// 使用自定义责任链路调用
AdditionChainContext.listChain(orderSourceList, orderTargetList,
OrderFieldHandler.class, StoreFieldHandler.class, CCCFieldHandler.class);