责任链模式 - 项目中的使用

设计模式-总览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);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值