为了提高java 模块化,降低代码耦合,将业务流程中的功能进行单一原则抽象,通过流程组件按照业务的场景,组合模块,来实现业务需求,强制代码实现符合单一原则,提高代码的可测试性,另外通过业务流程节点的组合显性的表达业务逻辑,可读性性更高
业务逻辑是由一系列的逻辑判断构成,如以下波次达收货流程,按照图中业务揽收的业务处理
按照流程图中的节点类型分为3类,
1、决策业务场景
2、校验执行条件
3、执行业务动作
如图,容器收货分为两个业务场景,三方作业、自营作业,
将“校验执行条件” ,“业务动作” 抽象成最小的单元,
优点:1、实现复用目的,2,降低测试复杂度,3,各业务场景,业务逻辑清晰
缺点:个节点都可能需要依赖数据,每个节点都需要访问数据性能会有开销,如复用数据会对节点间会产生依赖
本方案将复杂的流程图的从顶点到终点的边抽象成业务场景,对业务场景进行动态配置,通过配置达到扩展目标
如收货可分为2个场景,丹鸟收货和app收货两个业务场景
1、业务流程调用时序
2、组建加载
略
达到可发现,可使用,可管理
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());
}
}
如何选择那种实现方式
如何一个节点逻辑复杂,代码比较多,推荐使用 实现接口的方式
/**
* 业务场景
*/
@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;
}
目的:将业务流程图转化为 场景列表
Spring 加载完成后,开始装配 实现 ApplicationListener 接口 组装流程配置
public class SpecificationInitializer implements ApplicationListener{ }