Java 设计模式——状态模式(行为型设计模式)实战示例基于spring的状态机

Java 设计模式——状态模式(行为型设计模式)实战示例基于spring的状态机,第1张

Java 设计模式——状态模式(行为型设计模式)实战示例基于spring的状态机

说明:本文只是在个人实战中的示例,主要了解思想,代码可根据自己的具体情况进行调整,不是完整的demo代码。

背景说明

订单存在下单、支付、运输、完成等此类的状态流转,每一个状态下做不同的业务处理,状态存在变更的情况。
期望能够通过配置来实现状态变更时不影响历史代码并且不做变更,仅针对新状态进行业务开发即可。

方案说明

个人的解决方案是这样的,仅供参考:
1、状态具体的流转步骤通过配置文件完成
2、每个状态要做的业务逻辑面向接口开发
3、使用指令模式来进行控制
4、具体指令配置在配置文件中
5、指令就是状态code
6、通过策略模式进行封装仅对外暴露一个接口
7、通过桥连接模式将具体的状态机流转进行处理

代码 第一步、配置文件
  • 梳理自己所需要的状态,每一个状态code就是一个指令
  • 每一个指令对应了一个具体的业务接口实现类
  • 不同的产品可能有不同的状态流转,需要支持多产品集合

配置文件示例如下,代码仅供参考,可根据自己的业务进行不同的字段增减:
配置内容我写在了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 products = Lists.newArrayList();
}
@Data
public class StateMachineProduct {
    String name;
    Boolean open;
    List states = Lists.newArrayList();
}
@Data
public class StateMachineProductState {
    String service;
    String roles;
    String instructions;
    String des;
}
第二步、定义状态机接口

状态机具体执行的service接口定义

public interface OrderStateMachineService {
    
    OrderInstructionsStateVO execute(OrderInstructionsModel model);
    
    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;
	}
}
第四步、定义对外暴露的接口
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 products = stateMachineConfig.getProducts();
        for (StateMachineProduct stateMachineProduct: products) {
            String name = stateMachineProduct.getName();
            if(name.equals(productsName) && stateMachineProduct.getOpen()){
                List 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 #下一状态
大致的结构框架就是这样的。
也可以进行二次抽象,通过组合模式来实现不同的产品集状态组合。
另外还可以继续扩展,比如使用工厂模式来生产不同的状态机实现类或者再抽象一层,生产不同的产品。
大家可以扩散一下思维,欢迎来讨论和指点!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5685038.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存