说明:本文只是在个人实战中的示例,主要了解思想,代码可根据自己的具体情况进行调整,不是完整的demo代码。
订单存在下单、支付、运输、完成等此类的状态流转,每一个状态下做不同的业务处理,状态存在变更的情况。
期望能够通过配置来实现状态变更时不影响历史代码并且不做变更,仅针对新状态进行业务开发即可。
个人的解决方案是这样的,仅供参考:
1、状态具体的流转步骤通过配置文件完成
2、每个状态要做的业务逻辑面向接口开发
3、使用指令模式来进行控制
4、具体指令配置在配置文件中
5、指令就是状态code
6、通过策略模式进行封装仅对外暴露一个接口
7、通过桥连接模式将具体的状态机流转进行处理
配置文件示例如下,代码仅供参考,可根据自己的业务进行不同的字段增减:
配置内容我写在了bootstrap.yml文件中了,根据自己的业务进行调整
#自定义状态机
statemachine:
products: #产品集合
- name: gome_cuohe #产品标识
open: true #产品启用开关
states: #产品状态集合
#角色分别为:系统(SYSTEM)、雇主(A)、服务商(B)
- service: OrderStateMachineXXXServiceImpl #状态机需要执行的service
roles: A,B#支持的角色
instructions: xxx #指令
des: #描述
- service: OrderStateMachineSelectYYYServiceImpl #状态机需要执行的service
roles: B#支持的角色
instructions: yyy #指令
des: #描述
创建对应配置内容的映射java类
@Data
@Configuration
@ConfigurationProperties(prefix = "statemachine")
public class StateMachineConfig {
List<StateMachineProduct> products = Lists.newArrayList();
}
@Data
public class StateMachineProduct {
String name;
Boolean open;
List<StateMachineProductState> states = Lists.newArrayList();
}
@Data
public class StateMachineProductState {
String service;
String roles;
String instructions;
String des;
}
状态机具体执行的service接口定义
/**
* @author wwb
* @create 2021/5/12 11:54
* @desc 状态机具体执行的service接口定义
**/
public interface OrderStateMachineService {
/**
* @author wwb
* @create 2021/5/12 11:55
* @desc 具体执行状态流转的操作
**/
OrderInstructionsStateVO execute(OrderInstructionsModel model);
/**
* @author wwb
* @create 2021/5/12 11:55
* @desc 校验当前入参的指令是否允许执行下一状态
**/
boolean checkState(OrderInstructionsModel model);
}
入参Model
@Data
public class OrderInstructionsModel {
String productsName;//产品名称
String instructions;//指令
String role;//角色
Long userId;//用户ID
Object dto;//入参对象
}
出参VO
@Data
public class OrderInstructionsStateVO {
String code;
String msg;
Object data;
}
yml配置文件中每一个service都实现了OrderStateMachineService 接口
注意:Service的注解值对应yml文件中service的配置
下面的代码仅供参考:
@Slf4j
@Service("OrderStateMachineXXXServiceImpl")
public class OrderStateMachineXXXServiceImpl implements OrderStateMachineService {
@Transactional(rollbackFor = Exception.class)
@Override
public OrderInstructionsStateVO execute(OrderInstructionsModel model){
//TODO Your code
return null;
}
@Override
public boolean checkState(OrderInstructionsModel model){
//TODO Your check
return true;
}
}
@Slf4j
@Service("OrderStateMachineYYYServiceImpl")
public class OrderStateMachineYYYServiceImpl implements OrderStateMachineService {
@Transactional(rollbackFor = Exception.class)
@Override
public OrderInstructionsStateVO execute(OrderInstructionsModel model){
//TODO Your code
return null;
}
@Override
public boolean checkState(OrderInstructionsModel model){
//TODO Your check
return true;
}
}
/**
* @author wwb
* @create 2021/5/12 11:40
* @desc 对外暴露的状态机公共接口
**/
public interface OrderInstructionsService {
OrderInstructionsStateVO orderInstructions(OrderInstructionsModel model);
}
@Service
public class OrderInstructionsServiceImpl implements OrderInstructionsService {
@Autowired
private StateMachineConfig stateMachineConfig;//状态机配置,用于校验匹配
@Override
public OrderInstructionsStateVO orderInstructions(OrderInstructionsModel model) {
String instructions = model.getInstructions();
String productsName = model.getProductsName();
String role = model.getRole();
if(StringUtils.isEmpty(instructions) || StringUtils.isEmpty(productsName) || StringUtils.isEmpty(role)){
OrderInstructionsStateVO orderInstructionsStateVO = new OrderInstructionsStateVO();
orderInstructionsStateVO.setCode("404");
orderInstructionsStateVO.setMsg("参数不全");
return orderInstructionsStateVO;
}
List<StateMachineProduct> products = stateMachineConfig.getProducts();
for (StateMachineProduct stateMachineProduct: products) {
String name = stateMachineProduct.getName();
if(name.equals(productsName) && stateMachineProduct.getOpen()){
List<StateMachineProductState> states = stateMachineProduct.getStates();
for (StateMachineProductState stateMachineProductState : states) {
String instructionsState = stateMachineProductState.getInstructions();
String rolesState = stateMachineProductState.getRoles();
if(instructionsState.equals(instructions)){
if(rolesState.indexOf(role) != -1){
String service = stateMachineProductState.getService();
OrderStateMachineService stateService = (OrderStateMachineService) SpringContextUtil.getBean(service);
OrderInstructionsStateVO vo = stateService.execute(model);
return vo;
}
}
}
}
}
OrderInstructionsStateVO orderInstructionsStateVO = new OrderInstructionsStateVO();
orderInstructionsStateVO.setCode("400");
orderInstructionsStateVO.setMsg("未匹配到状态机");
return orderInstructionsStateVO;
}
}
目前我写到这个程度,还有很多可以优化的地方,优化的方向应该是:
只需要修改配置不影响具体的业务逻辑。
比如,增加指令:nextInstructions #下一状态
大致的结构框架就是这样的。
也可以进行二次抽象,通过组合模式来实现不同的产品集状态组合。
另外还可以继续扩展,比如使用工厂模式来生产不同的状态机实现类或者再抽象一层,生产不同的产品。
大家可以扩散一下思维,欢迎来讨论和指点!