设计模式|模板设计模式+职责链模式--顺序校验

本文介绍了如何使用模板设计模式和职责链模式优化数据导入时的顺序校验,避免繁琐的ifelse和多层循环,提高代码可读性和拓展性。通过创建一系列校验处理器,并在启动时指定校验顺序,实现了n^2时间复杂度的顺序校验流程,解决了大型后台管理系统中数据合法性校验的问题。
摘要由CSDN通过智能技术生成

顺序校验

       在真实的项目中,我们会遇到很多的校验问题,例如一个excel文件导入需要校验数据的合法性,且要按顺序校验,为此编码中会遇到很多的if else,部分复杂校验还需要嵌套多层循环,会出现很多n^3级别时间复杂度的代码,本文以博主实际案例,优化这样这一臃肿过程

场景描述

        小张是某大型后台管理系统的业务操作员,需要对清货管理模块添加清货数据,为此需要建立清货单据,由于之前老系统的原因,需要先从老系统中导出excel清货数据,再把excel导入到新系统,导入过程中需要校验清货单内的货品是否已经存在新系统中,且清货编码是否重复,单据是否存在等,校验步骤如下:

0#pic_center)

        以下介绍的实现方法,可能有些对象没有定义,博友可当成黑盒理解,不必计较其中内容,不妨碍理解本文。

实现方式

        定义共用的抽象方法(未选择接口的原因:需要有具体的实现方法,不是默认方法) AbstractHandler.java

**
 * 模板设计模式
 * ps:划定责任链调用模板方法
 *
 * @author dzx
 * @since 2020/10/26
 */
public abstract class AbstractHandler {

    private AbstractHandler handlerBase;

    /**
     * 指定下一级校验handler
     *
     * @param handlerBase handlerBase
     * @return HandlerBase
     */
    public AbstractHandler setNextHandler(AbstractHandler handlerBase) {
        this.handlerBase = handlerBase;
        return handlerBase;
    }

    /**
     * 获取下一个校验handler
     *
     * @return HandlerBase
     */
    public AbstractHandler getNextHandler() {
        return handlerBase;
    }
    
    /**
     * 校验抽象方法
     *
     * @param event             event 导入对象(含具体数据:单号-商品编码)
     * @param clearanceChainDto clearanceChainDto 校验过程中产生的结果对象
     * @param resultEvent resultEvent 校验成功后的反馈对象
     * @return boolean boolean 校验结果 true校验通过 false校验不通过
     */
    public abstract boolean doBulkFileTask(BulkFileTaskEvent.BulkFileTaskDetail event, DelistChainDTO clearanceChainDto,
                                           BulkFileTaskResultCallbackEvent resultEvent);
    
}

        校验是否存在该单据DelistCodeHandler.java

/**
 * 校验是否存在该单据
 *
 * @author dzx 
 * @since 2020/10/26
 */
@Component
public class DelistCodeHandler extends AbstractHandler {
    private static final String SUCCESS_MESSAGE = "校验成功,存在该单号";

    @Autowired
    private DelistOrderQuery delistQuery;


    @Override
    public boolean doBulkFileTask(BulkFileTaskEvent.BulkFileTaskDetail event,
                                  DelistChainDTO delistImportDto,
                                  BulkFileTaskResultCallbackEvent resultEvent) {
        boolean flag = false;
        //查询单号
        DelistOrderVO delistVo = delistQuery.queryDelistOrder(delistImportDto.getDelistImportEvent().getCode());
        if (Optional.ofNullable(delistVo).isPresent()) {
            resultEvent.getTaskDetails().add(BulkFileTaskResultCallbackEvent.BulkFileTaskDetailResult.builder()
                    .taskDetailId(event.getId())
                    .bulkFileTaskDetailStatus(BulkFileTaskDetailStatus.SUCCESS)
                    .message(SUCCESS_MESSAGE)
                    .build());
            //继续下一级校验 保留上一级校验的结果,以便后一级校验使用
            delistImportDto.setDelistOrderVO(delistVo);
            flag = getNextHandler().doBulkFileTask(event, delistImportDto, resultEvent);
        } else {
            resultEvent.getTaskDetails().add(BulkFileTaskResultCallbackEvent.BulkFileTaskDetailResult.builder()
                    .taskDetailId(event.getId())
                    .bulkFileTaskDetailStatus(BulkFileTaskDetailStatus.FAILURE)
                    .message(DelistOrderExceptionMsg.NO_EXIST_DELIST_CODE.getMsg())
                    .build());
        }
        return flag;
    }
}

        校验该单据状态是否为待提交DelistStatusHandler.java

/**
 * 校验该单据状态是否为待提交
 *
 * @author dzx
 * @since 2020/10/26
 */
@Component
public class DelistStatusHandler extends AbstractHandler {
    private static final String SUCCESS_MESSAGE = "校验成功,该单号为待提交状态";

    @Override
    public boolean doBulkFileTask(BulkFileTaskEvent.BulkFileTaskDetail event, DelistChainDTO delistChainDto, BulkFileTaskResultCallbackEvent resultEvent) {
        boolean flag = false;
        resultEvent.getTaskDetails().clear();
        if (UN_SUBMIT.name().equals(delistChainDto.getDelistOrderVO().getStatus())) {
            resultEvent.getTaskDetails().add(BulkFileTaskResultCallbackEvent.BulkFileTaskDetailResult.builder()
                    .taskDetailId(event.getId())
                    .bulkFileTaskDetailStatus(BulkFileTaskDetailStatus.SUCCESS)
                    .message(SUCCESS_MESSAGE)
                    .build());
            //继续下一级校验
            flag = getNextHandler().doBulkFileTask(event, delistChainDto, resultEvent);
        } else {
            resultEvent.getTaskDetails().add(BulkFileTaskResultCallbackEvent.BulkFileTaskDetailResult.builder()
                    .taskDetailId(event.getId())
                    .bulkFileTaskDetailStatus(BulkFileTaskDetailStatus.FAILURE)
                    .message(DelistOrderExceptionMsg.DELIST_STATUS_NO_UN_SUBMIT.getMsg())
                    .build());
        }
        return flag;
    }
}

        校验该单据下模号商品主数据是否存在DelistGoodsExistHandler.java

/**
 * 校验该单据下模号商品主数据是否存在
 * @author dzx 
 * @since 2020/10/26
 */
@Component
public class DelistGoodsExistHandler extends AbstractHandler {

    private static final String SUCCESS_MESSAGE = "校验成功,存在该模号";

    @Autowired
    private GoodsClient goodsClient;

    @Override
    public boolean doBulkFileTask(BulkFileTaskEvent.BulkFileTaskDetail event, DelistChainDTO delistChainDto, BulkFileTaskResultCallbackEvent resultEvent) {
        boolean flag = false;
        //查询该模号
        List<SimpleSpuCTO> simpleSpus = goodsClient.getSimpleSpus(SpuParams.builder().codes(Collections.singletonList(delistChainDto.getDelistImportEvent().getSpuCode())).build());
        resultEvent.getTaskDetails().clear();
        if (CollectionUtils.isNotEmpty(simpleSpus)) {
            resultEvent.getTaskDetails().add(BulkFileTaskResultCallbackEvent.BulkFileTaskDetailResult.builder()
                    .taskDetailId(event.getId())
                    .bulkFileTaskDetailStatus(BulkFileTaskDetailStatus.SUCCESS)
                    .message(SUCCESS_MESSAGE)
                    .build());
            flag = true;
        } else {
            resultEvent.getTaskDetails().add(BulkFileTaskResultCallbackEvent.BulkFileTaskDetailResult.builder()
                    .taskDetailId(event.getId())
                    .bulkFileTaskDetailStatus(BulkFileTaskDetailStatus.FAILURE)
                    .message(DelistOrderExceptionMsg.SPU_NO_EXIST.getMsg())
                    .build());
        }
        return flag;
    }
}

        借用springBoot的启动对象ApplicationRunner 项目启动过程中就指定好校验流程 DelistCheckOutChain.java

/**
 *
 * 责任链模式
 * 指定校验顺序
 * @author dzx
 * @since 2020/10/26
 */
@Component
public class DelistCheckOutChain implements ApplicationRunner {

    /**
     * 单号唯一性校验
     */
    @Autowired
    private DelistCodeHandler delistCodeHandler;

    /**
     * 单号状态校验
     */
    @Autowired
    private DelistStatusHandler delistStatusHandler;

    /**
     * 单号下货品是否存在
     */
    @Autowired
    private DelistGoodsExistHandler delistGoodsExistHandler;


    @Override
    public void run(ApplicationArguments args) {
        //链式指定校验流程
        delistCodeHandler.setNextHandler(delistStatusHandler)
                .setNextHandler(delistGoodsExistHandler);
    }
}

        最后的调用校验过程

@Service
@Slf4j
public class DelistOrderApplication {
    @Autowired
    private DelistOrderEventBus delistOrderEventBus;

    @Autowired
    private DelistCodeHandler delistCodeHandler;

    /**
     * 保存导入信息
     * @param  event event
     * @throws NotFoundException NotFoundException
     */
    public void saveClearanceBulkFile(BulkFileTaskEvent event) throws NotFoundException {
        //校验成功结果集合
        List<DelistImportEvent> delistImportEventList = new ArrayList<>(event.getTaskDetails().size());
        //
        List<DelistChainDTO> results = new ArrayList<>();
        //校验数据
        for (BulkFileTaskEvent.BulkFileTaskDetail bulkFileTaskDetail : event.getTaskDetails()) {
            //校验对象创建 ......
            //bulkFileTaskDetail导入对象 delistChainDto 存储校验过程中的产生的对象(对下一级有用) resultEvent校验结果存储
            //调用校验过程
            boolean flag = delistCodeHandler.doBulkFileTask(bulkFileTaskDetail, delistChainDto,resultEvent);
            delistOrderEventBus.sendDelistOrderOutput(resultEvent);
            //校验成功加入集合中
            if (flag){
                delistImportEventList.add(delistImportEvent);
                results.add(delistChainDto);
            }
        }
        //处理成功校验的数据
        orderService.doDelistBulkFile(delistImportEventList,results);
    }
}

总结

        使用模板加职责链模式可以指定校验顺序,有效减少if和else繁琐的嵌套问题,更加优雅的实现这一顺序校验的过程,使代码有更好的可读性和拓展性,本文使用的校验方式控制在n^2时间复杂度内,有另外一种实现方式为 n^3时间复杂度,其实现方式和上文最大的不同是校验过程中加入校验LinkedList,该LinkedList包含各种校验类,同时在项目启动时可以通过LinkedList的特性,保证插入顺序,来解决校验的顺序性问题,上文的实现方式空间复杂度会比这一种实现方式要高

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值