业务背景

  • 朴朴门店商品库存不足时,需要补货,但怎么补是有一定策略的.朴朴现在是自动补货,根据每个门店的每天销量,库存等信息通过大数据计算得到门店的补货量.
  • 举例说明:现在朴朴要给深圳的其中27家门店的A商品补货,假如现在大数据测算出来每家门店都要补货100,27门店算下来总共要补2700件,但真正去补货的时候可能会多补一些,比如补个2730件,因为大数据测算出来的数据不是100%准确的,会有误差.所有多补一些量的目的是防止售卖时,出现商品无库存的情况.那上面例子中2730件商品怎么去分摊到这27家门店呢?每家门店分摊到多少呢?肯定会有一些分摊规则,然后分摊总量按照分摊规则去分摊到每家门店。这个就是该需求所要做的事情.

现状分析

  • 现在分摊策略计算逻辑是放在python里,通过DAG去调用python中的逻辑去执行分摊计算,现由于架构升级的需要及复用性要求,需要把一键分摊逻辑抽到java代码中实现,形成单独功能模块,并对外提供统一接口调用.

 

 原型:

设计目标

  •  将python中的分摊计算逻辑迁移到java代码中,并支持分摊多灵活的配置(在城市商品模拟任务-执行,会使用该功能)。

 名词解释

  • 分摊:在门店补货的时候,一般要保证门店商品要有足够量的货,不要出现用户购买商品时出现“缺货”的场景,所以每次在补货的时候会稍微多补一点,保证门店商品的有货率。
  • 补货模拟:采销同学在系统上配置补货量,要模拟的城市+门店,系统会真实模拟出该商品的各个门店的补货量,供采销做参考
  • 举例:A商品,10个门店需要补货,,采销同学输入一个补货量(比如:800)的值,配置要模拟的城市+门店,然后系统会创建一个模拟任务,去模拟真实的补货场景。系统在执行完模拟任务后,会把各门店补货的结果展示到界面上,给采销同学查看。采销同学根据模拟的结果+采销个人的经验,输出补货的方案。而这个分摊策略计算,就是模拟任务执行中的一环.

需求分析

  • 3.1业务需求分析

  • 该需求其实就是分成3大块去顺序执行,分别是1.前置计算->2.分摊策略->3.差值分摊
  • 前置计算,分摊策略,差值分摊都可能有A,B,C三中类型去选择,具体如何选择,是按照你入参中的输入类型由策略模式去决定选择哪种

按照上面的原型所示,可以把原型中的逻辑抽象成下面截图所示的模型

 

由上图可以看出来,其中较为复杂的地方其实就是分摊步骤这个流程。整个流程分为5步,那如果后续需求变化,步骤由原来的5步变成了4步,或者变成了7步,这个怎么处理。所以这个地方要考虑做的更灵活,拓展性更好一些。其实可以按照设计模式中的组合模式去解决这个需求.

分摊步骤流程分析:

  • 1.其实可以把整个分摊步骤看成类似于一颗树的结构,比如根节点有两个子节点,如上面截图所示,执行逻辑的时候,从根节点出发,根据"判断条件"选择对应的子节点分支执行,执行完子节点后,再看子节点它有没有子节点,如果有,就再执行子节点的子节点。这个流程就类似于二叉树的前序遍历。
  • 2.既然把这个需求看成1颗树,那树的定义和树的遍历最好分开.如果你的执行流程总共是5步,那我定义的树就是层级为5的树,如果你的执行流程是7步,那我定义的树就是层级为7的树。不管你需求怎么变化,要变的逻辑就只是树的定义逻辑,而树的遍历逻辑是不用变化的。

 

 四 概要设计

  • 4.1业务流程

4.2.功能模块

模块内容         模块描述
前置计算 计算期初库存等值,方便后面计算流程使用(配置化)
分摊步骤 分摊总量按照分摊步骤中的步骤一层层去分摊(配置化)
差值分摊 门店分摊量均计算完后,不一定=校正分摊总量,此时要对差值进行扣减或增加(配置化)
配置管理 如果配置的值为:A_B_C,其中A表示前置计算走A类型的计算,B表示分摊步骤计算走B类型的分摊步骤计算,C表示差值分摊走C类型的差值分摊计算

五 详细设计

  • 5.1 模块设计

  • 5.1.1前置计算

  • 5.1.2分摊步骤流程:

  •  树的定义:

  • 下面的arrangeStepOrder方法,其实就是在定义1颗树.维护好根节点以及其子节点的关系.如果后面需求变更,比如:后续需求要把原来的"第5步骤-门店订货上限",去掉,那我直接在下面的"编排分摊步骤执行顺序"方法中,把第5个步骤注释掉就可以,其他地方的逻辑都不用动.
  • public class ProportionAllocationStepAggr extends AbstractAllocationStepAggregateRoot {
    
        /**
         * 编排分摊步骤执行顺序
         */
        @Override
        protected AbstractCalculationStep arrangeStepOrder() {
            //第5步骤-门店订补货上限
            ProportionMaxStockQuantityAllocationStep proportionMaxStockQuantityAllocationStep =new ProportionMaxStockQuantityAllocationStep();
    
            //第4步骤-按照销量分摊比例来分摊
            ProportionSalesProportionAllocationStep proportionSalesProportionAllocationStep = new ProportionSalesProportionAllocationStep();
            proportionSalesProportionAllocationStep.addChildrenStep(proportionMaxStockQuantityAllocationStep);
    
            //第3步骤-按照安全库存来分摊
            ProportionSafeStockAllocationGreaterThanStep proportionSafeStockAllocationGreaterThanStep = new ProportionSafeStockAllocationGreaterThanStep();
            proportionSafeStockAllocationGreaterThanStep.addChildrenStep(proportionSalesProportionAllocationStep);
    
            ProportionSafeStockAllocationLessThanStep proportionSafeStockAllocationLessThanStep = new ProportionSafeStockAllocationLessThanStep();
            proportionSafeStockAllocationLessThanStep.addChildrenStep(proportionMaxStockQuantityAllocationStep);
    
            //第2步骤-按照销量来分摊
            ProportionSaleNumAllocationLessThanStep proportionSaleNumAllocationLessThanStep = new ProportionSaleNumAllocationLessThanStep();
            proportionSaleNumAllocationLessThanStep.addChildrenStep(proportionMaxStockQuantityAllocationStep);
    
            ProportionSaleNumAllocationGreaterThanStep proportionSaleNumAllocationGreaterThanStep = new ProportionSaleNumAllocationGreaterThanStep();
            proportionSaleNumAllocationGreaterThanStep.addChildrenStep(proportionSafeStockAllocationGreaterThanStep);
            proportionSaleNumAllocationGreaterThanStep.addChildrenStep(proportionSafeStockAllocationLessThanStep);
    
            //第1步骤-库存预警
            ProportionWarningStockQuantityAllocationGreaterThanStep proportionWarningStockQuantityAllocationGreaterThanStep = new ProportionWarningStockQuantityAllocationGreaterThanStep();
            proportionWarningStockQuantityAllocationGreaterThanStep.addChildrenStep(proportionSaleNumAllocationLessThanStep);
            proportionWarningStockQuantityAllocationGreaterThanStep.addChildrenStep(proportionSaleNumAllocationGreaterThanStep);
    
            ProportionWarningStockQuantityAllocationLessThanStep proportionWarningStockQuantityAllocationLessThanStep = new ProportionWarningStockQuantityAllocationLessThanStep();
            proportionWarningStockQuantityAllocationLessThanStep.addChildrenStep(proportionMaxStockQuantityAllocationStep);
      
            //根节点
            ProportionRootStep proportionRootStep = new ProportionRootStep();
            proportionRootStep.addChildrenStep(proportionWarningStockQuantityAllocationGreaterThanStep);
            proportionRootStep.addChildrenStep(proportionWarningStockQuantityAllocationLessThanStep);
    
         //返回根节点
            return proportionRootStep;
        }
    }

 分摊步骤抽象类(节点抽象类)

public abstract class AbstractCalculationStep {
   //执行该节点的业务逻辑
    public abstract void executeStep(AllocationApplicationDTO mainStoreReplenishALLParamVO);
  
   //获取该节点下的所有子节点
    public abstract List<AbstractCalculationStep> getChildrenStep();

  //新增子节点
    public abstract void addChildrenStep(AbstractCalculationStep childStep);

}

  根节点(继承分摊步骤抽象类)

public class ProportionRootStep extends AbstractCalculationStep {
    private List<AbstractCalculationStep> childrens = Lists.newArrayList();

    @Override
    public void executeStep(AllocationApplicationDTO mainStoreReplenishALLParamVO) {
     //获取该节点下的所有子节点,并执行子节点的executeStep方法
        this.getChildrenStep().forEach(child->{
        //执行子节点自己的业务逻辑
            child.executeStep(mainStoreReplenishALLParamVO);
        });
    }

  //获取当前节点下的所有子节点
    public List<AbstractCalculationStep> getChildrenStep() {
        return this.childrens;
    }

  //新增子节点到当前节点
    @Override
    public void addChildrenStep(AbstractCalculationStep childStep) {
        this.childrens.add(childStep);
    }
}
  •  树的遍历:

  • public abstract class AbstractAllocationStepAggregateRoot {
    
        public void executeAllocationSteps(AllocationApplicationDTO mainStoreReplenishALLParamVO){
            //编排分摊步骤执行顺序,拿到根节点
            AbstractCalculationStep rootStep = arrangeStepOrder();
    
            //从根节点开始遍历,执行每一个分摊步骤(树型结构)
            rootStep.executeStep(mainStoreReplenishALLParamVO);
        }
    
        protected abstract AbstractCalculationStep arrangeStepOrder();
    }

  

  • 5.1.3差值分摊

 

posted on 2024-11-16 13:00  路飞_lufei  阅读(21)  评论(0编辑  收藏  举报