后端与系统架构4577 字

阿里内部设计模式最佳实践

·全库 553 / 611

《阿里内部设计模式最佳实践》共 0.5 万字,通篇围绕 场景、落地、对齐、日志 展开,归在「后端与系统架构」这一层。

覆盖场景落地对齐日志成本

适合给 AI 系统搭底座、要管得住的人

目录骨架(3 节)
  1. 一 业务场景描述
  2. 二 设计模式
  3. 三 总结

示例代码

注:将ppt后缀名改为zip后解压

jdk版本:1.8.0_181

​

本次分享内容

  1. 业务场景描述
  2. 设计模式(模板方法模式、策略模式、工厂模式、代理模式)
  3. 总结

本节课重点在于说明工作中所使用的设计模式,为了能够更好的理解设计模式,首先简单介绍一下业务场景。使用设计模式,可以简化代码、提高扩展性、可维护性和复用性。有哪些设计模式,这里就不再介绍了,网上很多, 本次只介绍所用到设计模式。

一 业务场景描述

1 意义

本次业务场景为线路检查工具,为什么需要线路检查工具呢,有以下几个方面的原因:

  • 每逢大促都需要进行各网络和各行业的线路调整,调整完成之后,是否得到期望状态,需要检查确认。
  • 上下游应用之间数据的一致性检查,如果存在不一致,可能会在订单履行时造成卡单。
  • 有些问题发生后,业务同学需要全面检查一遍线路数据,判断是否符合预期。
  • 各领域之间的数据变更缺乏联动性,导致资源和线路出现不一致。

为什么要把线路检查工具产品化呢,考虑如下:

  • 以前每次大促,都是技术同学现场编写代码捞数据给到业务同学,而且因为人员流动性较大,代码可复用性较低,导致重复劳动。产品化后,可以方便地传承下去,避免不必要的重复劳动。
  • 每次因为时间紧急,现场写的代码都比较简单,经常是直接将数据打印到标准输出,然后复制出来,人工拆分转成 Excel 格式;这样的过程要进行多次,占用太多技术同学的时间。产品化后,解放了技术同学,业务同学可以自己在页面操作。
  • 很多数据检查,是每次大促都会进行的,业务同学与技术同学之间来回沟通的成本较高。产品化后,可以避免这些耗时耗力的沟通,大家可以把更多的时间放在其他的大促保障工作上。

2 检查项

根据 2020 年 D11 进行的数据检查,本次共实现 8 项,下面列举了 4 项,如下:

  • 时效对齐检查:确保履行分单正常。
  • 弱控线路与表达网络一致性:确保履行和路由不会因为线路缺失而卡单。
  • 资源映射和编码映射一致:前者是表达线路时所用,后者是订单履约时所用,确保表达和履约能够一致。
  • 检查线路数量:统计现存线路的情况。

好了,了解了背景知识,下面开始介绍所用到的设计模式,以及为什么要用、怎么用。

二 设计模式

1 模板方法模式 + 泛型

上述 8 项数据检查工具,大致的处理流程是类似的,如下:

针对不同的检查工具,只有 “线路数据检查” 这一步是不一样的逻辑,其他步骤都是相同的,如果每个检查工具都实现这么一套逻辑,必定造成大量的重复代码,维护性较差。

模板方法模式能够很好地解决这个问题。模板方法设计模式包含模板方法和基本方法,模板方法包含了主要流程;基本方法是流程中共用的逻辑,如创建检查任务,结果输出等等。

下图是所实现的模板方法模式的类继承关系:

分析如下:

1)DataCheckProductService 接口为对外提供的服务,dataCheck 方法为统一的数据检查接口。

2)AbstractDataCheckProductService 是一个抽象类,设定模板,即在 dataCheck 方法中设定好流程,包括如下:

  • commonParamCheck 方法:进行参数合法性检查,不合法的情况下,直接返回。
  • createFileName 方法:创建文件名称。
  • createTaskRecord 方法:创建检查任务。
  • runDataCheck 方法:进行数据检查,这是一个抽象方法,所有检查工具都要实现此方法,以实现自己的逻辑。
  • uploadToOSS 方法:将检查结果上传到 OSS,便于下载。
  • updateRouteTask 方法:结束时更新任务为完成。

dataCheck 方法为模板方法,runDataCheck 方法由各个子类去实现,其他方法是基本方法。还有一些其他方法,是各个检查工具都需要使用的,所以就放在了父类中。

3)CheckSupplierAndCodeMappingService 类、CheckLandingCoverAreaService 类和 CheckAncPathNoServiceService 类为具体的检查工具子类,必须实现 runDataCheck 方法。

因为不同检查项检的查结果的格式是不一样的,所以使用了泛型,使得可以兼容不同的检查结果。

简化的代码如下:

/**
 * 数据检查工具产品化对外服务接口
 * @author xxx
 * @since xxx
 * */
public interface DataCheckProductService {
    /**
     * 数据检查
     * @param requestDTO 请求参数
     * */
    <T> BaseResult<Long> dataCheck(DataCheckRequestDTO requestDTO);
}
/**
 * 数据检查工具产品化服务
 *
 * @author xxx
 * @since xxx
 * */
public abstract class AbstractDataCheckProductService implements DataCheckProductService {
    /**
     * 数据检查
     * @param requestDTO 请求参数
     * @return
     * */
    @Override
    public <T> BaseResult<Long> dataCheck(DataCheckRequestDTO requestDTO){
        try{
            //1. 参数合法性检查
            Pair<Boolean,String> paramCheckResult = commonParamCheck(requestDTO);
            if(!paramCheckResult.getLeft()){
                return BaseResult.ofFail(paramCheckResult.getRight());
            }
            //2. 创建导出任务
            String fileName = createFileName(requestDTO);
            RouteTaskRecordDO taskRecordDO = createTaskRecord(fileName, requestDTO.getUserName());
            //3. 进行数据检查
            List<T> resultList = Collections.synchronizedList(new ArrayList<>());
            runDataCheck(resultList, requestDTO);
            //4. 写入文件
            String ossUrl = uploadToOSS(fileName,resultList);
            //5. 更新任务为完成状态
            updateRouteTask(taskRecordDO.getId(),DDportTaskStatus.FINISHED.intValue(), resultList.size()-1,"",ossUrl);
            return BaseResult.ofSuccess(taskRecordDO.getId());
        }catch (Exception e){
            LogPrinter.errorLog("dataCheck-error, beanName="+getBeanName(),e);
            return BaseResult.ofFail(e.getMessage());
        }
    }
    /**
     * 进行数据检查
     * @param resultList 存放检查结果
     * @param requestDTO 请求参数
     * @return
     * */
    public abstract <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO);
}
/**
 * 检查资源映射和编码映射一致
 * @author xxx
 * @since xxx
 * */
public class CheckSupplierAndCodeMappingService extends AbstractDataCheckProductService{
    @Override
    public <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO){
        //自己的检查逻辑
    }
}
/**
 * 检查区域内落地配必须三级全覆盖
 * @author xxx
 * @since xxx
 * */
public class CheckLandingCoverAreaService extends AbstractDataCheckProductService{
    @Override
    public <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO){
        //自己的检查逻辑
    }
}
/**
 * 检查资源映射和编码映射一致
 * @author xxx
 * @since xxx
 * */
public class CheckAncPathNoServiceService extends AbstractDataCheckProductService{
    @Override
    public <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO){
        //自己的检查逻辑
    }
}

资料里没有你的场景?

把你手上的数据和想解决的那个环节发上来,我们按具体情况回,不复述方法论。

发布需求