可配置的业务流程组件的设计与实现

使用场景

        为了提高java 模块化,降低代码耦合,将业务流程中的功能进行单一原则抽象,通过流程组件按照业务的场景,组合模块,来实现业务需求,强制代码实现符合单一原则,提高代码的可测试性,另外通过业务流程节点的组合显性的表达业务逻辑,可读性性更高

抛出问题

业务逻辑是由一系列的逻辑判断构成,如以下波次达收货流程,按照图中业务揽收的业务处理

按照流程图中的节点类型分为3类,

1、决策业务场景

2、校验执行条件

3、执行业务动作

如图,容器收货分为两个业务场景,三方作业、自营作业,

可配置的业务流程组件的设计与实现_第1张图片

将“校验执行条件” ,“业务动作” 抽象成最小的单元,

优点:1、实现复用目的,2,降低测试复杂度,3,各业务场景,业务逻辑清晰

缺点:个节点都可能需要依赖数据,每个节点都需要访问数据性能会有开销,如复用数据会对节点间会产生依赖

本方案将复杂的流程图的从顶点到终点的边抽象成业务场景,对业务场景进行动态配置,通过配置达到扩展目标

如收货可分为2个场景,丹鸟收货和app收货两个业务场景

实现方案

时序图


1、业务流程调用时序

可配置的业务流程组件的设计与实现_第2张图片

2、组建加载

  略

1、领域模型

1.1 定义核心执行类:

达到可发现,可使用,可管理

public interface ISopSpecification {

     String getCode();

     String getName();

     boolean isAction();
     /**
      * 检查
      * @param specificationContext
      */
     void execute(SpecificationContext specificationContext);
}

通用调用参数

@Data
public class SpecificationContext {
  
    @NotNull
    public String operateFlowType;
    /**
     * 操作对象
     */
    @NotNull
    private String bizOrderNo;

    /**
     * 业务单号类型 容器,令牌,履约单
     */
    @NotNull
    private String bizOrderNoType;

    /**
     * 作业节点,事件
     */
    @NotNull
    private String bizOperatorNode;

    /**
     * 实效心智
     */
    @NotNull
    private String timeMind;

    /**
     * 配送平台,app ,api
     */
    @NotNull
    private String deliveryPlatform;

    /**
     * 供应商code
     */
    @NotNull
    private String supplierCode;
    /**
     * 可扩展参数
     */
    @NotNull
    private Map extendParam;
}

1.1.1 ISopSpecification 实现方式

方式1: 直接实现:ISopSpecification

@Component
public class DelivererShipOperatorSpecification implements ISopSpecification {
    @Override
    public String getCode() {
        return "DELIVERY_DELIVERER_CHECK";
    }

    @Override
    public String getName() {
        return "配送作业-配送员校验";
    }

    @Override
    public boolean isAction() {
        return true;
    }

    @Override
    public void execute(SpecificationContext specificationContext) {

        DeliverySpecificationContext context = (DeliverySpecificationContext) specificationContext;
        //履约单是否被他人领取
        checkOrderShipByOther(context);
        //令牌是否被他人领取
        checkPackageShipByOther(context);
        //判断是否分配给其他供应商
        checkAssignOtherSupplier(context);
    }

}

方式2: 使用注解方案实现

核心注解

流程中的业务节点

public @interface SpecActionNode {
    String getCode();
    String getName();
}
流程中的校验节点
public @interface SpecCheckNode {
    String getCode();
    String getName();
}
流程中的决策节点
public @interface SpecSceneNode {
    String getCode();
    String getName();
}

构造器
public @interface SpecFactory {
    String getCode();
    String getName();
}

实现示例

@SpecFactory(getCode = "ReceiveOrderExec", getName = "收货单作业流程" )
@Slf4j
@Component
public class ReceiveOrderEventsImpl implements ReceiveOrderEvents {
    @Override
    public void receive(DockReceiveSpecCheckContext checkContext) {
        checkContext.setOperateFlowType(OperateFlowTypeEnum.ORDER_DOCK_RECEIVE.getType());
        checkContext.setDeliveryPlatform(DeliveryPlatformEnum.APP.getType());
        dockReceiveSpecificationCheck.execute(checkContext);
    }
    @SpecCheckNode(getCode = "RECEIVE_ORDER_EXEC_CHECKBOX", getName = "收货容器校验")
    public void checkBox(DockReceiveSpecCheckContext drsContent) throws DmsCommonException {
    
    }

    @SpecCheckNode(getCode = "RECEIVE_ORDER_EXEC_CHECK_STATUS", getName = "收货状态校验")
    public void checkStatus(DockReceiveSpecCheckContext checkContext) throws DmsCommonException {
        
    }

    @SpecActionNode(getCode = "RECEIVE_ORDER_EXEC", getName = "容器收货")
    public void action(DockReceiveSpecCheckContext checkContext) {
       
    }

    @SpecActionNode(getCode = "RECEIVE_ORDER_NOTIFIY_FULFILL", getName = "回传履约")
    public void notifyFulfill(DockReceiveSpecCheckContext checkContext) {
        deliveryOrderPackageComponent.sendReceiveMsg(checkContext.getDeliveryDockCode(),checkContext.getReceiveOrderCode(),checkContext.getOperatorName(),checkContext.getContainerCode(),new Date());
    }
}

如何选择那种实现方式

如何一个节点逻辑复杂,代码比较多,推荐使用 实现接口的方式

1.2 定义业务场景类

/**
 * 业务场景
 */
@Data
public class BizScenario {
    /**
     * 业务场景名称
     */
    private String name ;

    /**
     * 业务场景code
     */
    private String code ;

    /**
     * 操作类型 业务流程ID 
     */
    private String operateFlowType;

    /**
     * 操作类型如到站
     */
    private String operateFlowTypeName;
    /**
     * 业务执行列表
     */
    private List sopSpecifications;

    /**
     * groovy 脚本用于设置匹配条件
     */
    private String matchCondition;

}

目的:将业务流程图转化为 场景列表

1.3 流程装配

Spring 加载完成后,开始装配 实现 ApplicationListener 接口 组装流程配置

public class SpecificationInitializer 
    implements ApplicationListener {
}

你可能感兴趣的:(java,架构)