使用场景
为了提高java 模块化,降低代码耦合,将业务流程中的功能进行单一原则抽象,通过流程组件按照业务的场景,组合模块,来实现业务需求,强制代码实现符合单一原则,提高代码的可测试性,另外通过业务流程节点的组合显性的表达业务逻辑,可读性性更高
抛出问题
业务逻辑是由一系列的逻辑判断构成,如以下波次达收货流程,按照图中业务揽收的业务处理
按照流程图中的节点类型分为3类,
1、决策业务场景
2、校验执行条件
3、执行业务动作
如图,容器收货分为两个业务场景,三方作业、自营作业,
将“校验执行条件” ,“业务动作” 抽象成最小的单元,
优点:1、实现复用目的,2,降低测试复杂度,3,各业务场景,业务逻辑清晰
缺点:个节点都可能需要依赖数据,每个节点都需要访问数据性能会有开销,如复用数据会对节点间会产生依赖
本方案将复杂的流程图的从顶点到终点的边抽象成业务场景,对业务场景进行动态配置,通过配置达到扩展目标
如收货可分为2个场景,丹鸟收货和app收货两个业务场景
实现方案
时序图
1、业务流程调用时序
2、组建加载
略
1、领域模型
1.1 定义核心执行类:
达到可发现,可使用,可管理
public interface ISopSpecification { String getCode(); String getName(); boolean isAction(); /*** 检查* @param specificationContext*/ void execute(SpecificationContext specificationContext);}
通用调用参数
@Datapublic class SpecificationContext {@NotNullpublic String operateFlowType;/** * 操作对象 */@NotNullprivate String bizOrderNo;/** * 业务单号类型 容器,令牌,履约单 */@NotNullprivate String bizOrderNoType;/** * 作业节点,事件 */@NotNullprivate String bizOperatorNode;/** * 实效心智 */@NotNullprivate String timeMind;/** * 配送平台,app ,api */@NotNullprivate String deliveryPlatform;/** * 供应商code */@NotNullprivate String supplierCode;/** * 可扩展参数 */@NotNullprivate Map extendParam;}
1.1.1 ISopSpecification 实现方式
方式1: 直接实现:ISopSpecification
@Componentpublic class DelivererShipOperatorSpecification implements ISopSpecification {@Overridepublic String getCode() {return "DELIVERY_DELIVERER_CHECK";}@Overridepublic String getName() {return "配送作业-配送员校验";}@Overridepublic boolean isAction() {return true;}@Overridepublic 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@Componentpublic class ReceiveOrderEventsImpl implements ReceiveOrderEvents {@Overridepublic 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 定义业务场景类
/** * 业务场景 */@Datapublic 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 {}