xml实现状态机

刚换了一家公司,学习了公司内部的项目,带我的师兄让我学习下公司项目中状态机的实现,并自己实现一个状态机。以此来记录学习状态机的过程。

https://blog.csdn.net/xinghuanmeiying/article/details/81586954

通过这篇博文学习了状态机图如何绘制,以及状态机图中的一些概念,不清楚的状态机的小伙伴可以学习下。(不知道这算不算侵权哈,反正自己也是通过别人的博客学习的)。

博客的末尾处一张图很有意思。在这里插入图片描述
简洁明了的解释了工作中某岗位的爱恨情仇啊,接下来就使用java语言简单实现这张状态机图吧。

先说一下实现的具体思路。

1.状态机图由各种状态(state)以及操作(operation)组成。
2.每个状态都是通过某种操作达到另一种状态。
3.熟悉设计模式的小伙伴可能会联想到责任链设计模式,单个对象通过维护一个next对象,来达到节点状态的扭转。

具体实现:
说在前面的话,状态机的代码具体实现有很多种,其中包括大名鼎鼎的spring也对状态机进行了实现(spring statemachine),状态机适用于多种业务线以及每条业务线存在很多状态的场景,使用状态,操作维护了某一个业务流程,是的复杂繁琐的流程把控变得简洁起来。我这里实现的思路是通过一个xml文件,定义一些操作,状态。在每个状态下可以执行哪些操作,以及执行完之后所对应的状态来实现状态机的。

<?xml version="1.0" encoding="UTF-8"?>
<state-action xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:noNamespaceSchemaLocation="state-action-1.2.xsd">

    <operations id="beikaifada" name="被开发打" >
            <operation name="beikaifada" i18n="被开发打" url="/beikaifada"/>
    </operations>
    <operations id="yangshangchenggong" name="养伤成功" >
            <operation name="yangshangchenggong" i18n="养伤成功"  url="/yangshangchenggong"/>
    </operations>
    <operations id="yangshangshibai" name="养伤失败" >
            <operation name="yangshangshibai" i18n="养伤失败" url="/yangshangshibai"/>
    </operations>
    <operations id="lingdaobumanyiduini" name="领导不满意怼你" >
            <operation name="lingdaobumanyiduini" i18n="领导不满意怼你" url="/lingdaobumanyiduini"/>
    </operations>
    <operations id="yangshangchenggonggaixuqiuchenggong" name="养伤成功改需求成功" >
            <operation name="yangshangchenggonggaixuqiuchenggong" i18n="养伤成功改需求成功" url="/yangshangchenggonggaixuqiuchenggong"/>
    </operations>
    <operations id="gaixuqiuchenggong" name="修改需求成功" >
            <operation name="gaixuqiuchenggong" i18n="修改需求成功" url="/gaixuqiuchenggong"/>
    </operations>
    <operations id="lingdaobumanyi" name="领导不满意" >
            <operation name="lingdaobumanyi" i18n="领导不满意" url="/lingdaobumanyi"/>
    </operations>
    <operations id="gaixuqiu" name="改需求" >
            <operation name="gaixuqiu" i18n="改需求" url="/gaixuqiu"/>
    </operations>
    <operations id="siwang" name="死亡" >
        <operation name="siwang" i18n="改需求" url="/siwang"/>
    </operations>

    <!-- 状态机主要流程 -->
    <states statusFiledName="status">
        <state id="startstate" name="startstate" i18n="开始">
           <operations ref="gaixuqiu" to="gaixuqiustate"/>
        </state>
        <state id="gaixuqiustate" name="gaixuqiustate" i18n="改需求">
            <operations ref="beikaifada" id="beikaifada" to="yangshangstate"/>
            <operations ref="gaixuqiuchenggong" id="gaixuqiuchenggong" to="zuohuibaostate"/>
        </state>
        <state id="yangshangstate" name="yangshangstate" i18n="养伤">
            <operations ref="yangshangshibai" id="yangshangshibai" to="siwangstate"/>
            <operations ref="yangshangchenggong" id="yangshangchenggong" to="gaixuqiustate"/>
            <operations ref="yangshangchenggonggaixuqiuchenggong" id="yangshangchenggonggaixuqiuchenggong" to="zuohuibaostate"/>
        </state>
        <state id="zuohuibaostate" name="zuohuibaostate" i18n="做汇报">
            <operations ref="lingdaobumanyi" id="lingdaobumanyi" to="gaixuqiustate"/>
            <operations ref="lingdaobumanyiduini" id="lingdaobumanyiduini" to="yangshangstate"/>
        </state>
        <state id="siwangstate" name="siwangstate" i18n="死亡">
            <operations ref="siwang" id="siwang" to="siwangstate"/>
        </state>
    </states>

</state-action>

根据那张爱恨情仇图片定义了一些具体操作,每个操作可以拥有一些标志,比如某操作执行对应到项目中某个方法,都可以在这边定义。

<operations id="beikaifada" name="被开发打" >
            <operation name="beikaifada" i18n="被开发打" url="/beikaifada"/>
    </operations>
    <operations id="yangshangchenggong" name="养伤成功" >
            <operation name="yangshangchenggong" i18n="养伤成功"  url="/yangshangchenggong"/>
    </operations>
    <operations id="yangshangshibai" name="养伤失败" >
            <operation name="yangshangshibai" i18n="养伤失败" url="/yangshangshibai"/>
    </operations>
    <operations id="lingdaobumanyiduini" name="领导不满意怼你" >
            <operation name="lingdaobumanyiduini" i18n="领导不满意怼你" url="/lingdaobumanyiduini"/>
    </operations>
    <operations id="yangshangchenggonggaixuqiuchenggong" name="养伤成功改需求成功" >
            <operation name="yangshangchenggonggaixuqiuchenggong" i18n="养伤成功改需求成功" url="/yangshangchenggonggaixuqiuchenggong"/>
    </operations>
    <operations id="gaixuqiuchenggong" name="修改需求成功" >
            <operation name="gaixuqiuchenggong" i18n="修改需求成功" url="/gaixuqiuchenggong"/>
    </operations>
    <operations id="lingdaobumanyi" name="领导不满意" >
            <operation name="lingdaobumanyi" i18n="领导不满意" url="/lingdaobumanyi"/>
    </operations>
    <operations id="gaixuqiu" name="改需求" >
            <operation name="gaixuqiu" i18n="改需求" url="/gaixuqiu"/>
    </operations>
    <operations id="siwang" name="死亡" >
        <operation name="siwang" i18n="改需求" url="/siwang"/>
    </operations>

接下来就是在状态中维护这些操作,我们参考状态机图,定义如下:

<!-- 状态机主要流程 -->
    <states statusFiledName="status">
        <state id="startstate" name="startstate" i18n="开始">
           <operations ref="gaixuqiu" to="gaixuqiustate"/>
        </state>
        <state id="gaixuqiustate" name="gaixuqiustate" i18n="改需求">
            <operations ref="beikaifada" id="beikaifada" to="yangshangstate"/>
            <operations ref="gaixuqiuchenggong" id="gaixuqiuchenggong" to="zuohuibaostate"/>
        </state>
        <state id="yangshangstate" name="yangshangstate" i18n="养伤">
            <operations ref="yangshangshibai" id="yangshangshibai" to="siwangstate"/>
            <operations ref="yangshangchenggong" id="yangshangchenggong" to="gaixuqiustate"/>
            <operations ref="yangshangchenggonggaixuqiuchenggong" id="yangshangchenggonggaixuqiuchenggong" to="zuohuibaostate"/>
        </state>
        <state id="zuohuibaostate" name="zuohuibaostate" i18n="做汇报">
            <operations ref="lingdaobumanyi" id="lingdaobumanyi" to="gaixuqiustate"/>
            <operations ref="lingdaobumanyiduini" id="lingdaobumanyiduini" to="yangshangstate"/>
        </state>
        <state id="siwangstate" name="siwangstate" i18n="死亡">
            <operations ref="siwang" id="siwang" to="siwangstate"/>
        </state>
    </states>

这里面对每一个状态执行的动作,以及执行完之后对应的状态都进行了定义,这样使得繁琐的状态机图一目了然。

接下来的实现就很简单了,对xml进行解析,维护成一个对象,放在内存中。

 public  Map<String,List<OperationDto>> init(){
        Map<String,List<OperationDto>> dataSource=new HashMap<>();
        try {
            File file = new File("/Users/fengyue/IdeaProjects/state_machine_demo/src/main/resources/lassen_suit.state-action.xml");

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder =  factory.newDocumentBuilder();
            Document doc = builder.parse(file);

            NodeList state = doc.getElementsByTagName("state");

            for (int i = 0; i < state.getLength(); i++) {
                List<OperationDto> operations = new ArrayList<>();
                Node node = state.item(i);
                NamedNodeMap nodeMap = node.getAttributes();
                String stateStr = nodeMap.getNamedItem("id").getNodeValue();

                //------------------开始解析operation--------------------
                NodeList childNodes = ((DeferredElementImpl)node).getElementsByTagName("operations");
                for (int j = 0; j < childNodes.getLength(); j++) {
                    OperationDto dto=new OperationDto();
                    Node item = childNodes.item(j);
                    String operationCode = item.getAttributes().getNamedItem("ref").getNodeValue();
                    String to = item.getAttributes().getNamedItem("to").getNodeValue();
                    dto.setCode(operationCode);
                    dto.setTo(to);

                    operations.add(dto);
                }
                dataSource.put(stateStr,operations);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataSource;
    }

因为只是简单对demo,所以每个操作都做成了一个请求,写在了controller中。

package com.example.state_machine_demo.Controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.example.state_machine_demo.dto.ActionState;
import com.example.state_machine_demo.dto.OperationDto;
import com.example.state_machine_demo.util.Index;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {

    public static final Map<String,String> stateMap=new HashMap<String,String>();
    public static final Map<String,String> operationMap=new HashMap<String,String>();

    static {
        stateMap.put("startstate","开始");
        stateMap.put("gaixuqiustate","改需求");
        stateMap.put("yangshangstate","养伤");
        stateMap.put("zuohuibaostate","做汇报");
        stateMap.put("siwangstate","死亡");

        operationMap.put("beikaifada","被开发打");
        operationMap.put("yangshangchenggong","养伤成功");
        operationMap.put("yangshangshibai","养伤失败");
        operationMap.put("lingdaobumanyiduini","领导不满意怼你");
        operationMap.put("yangshangchenggonggaixuqiuchenggong","养伤成功改需求成功");
        operationMap.put("gaixuqiuchenggong","修改需求成功");
        operationMap.put("lingdaobumanyi","领导不满意");
        operationMap.put("gaixuqiu","改需求");
        operationMap.put("siwang","死亡");
    }


    @Autowired
    private Index util;

    @GetMapping("/index")
    public ModelAndView index(@RequestParam String operation) {
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get("startstate");

        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }
        List<OperationDto> dtoList = list.stream().filter(e -> operation.equals(e.getCode())).collect(
            Collectors.toList());
        if(null == dtoList || dtoList.size()==0){
            return view;
        }

        view.addObject("state",stateMap.get("startstate"));
        view.addObject("operationList",dtos);
        return view;
    }


    @GetMapping("/beikaifada")
    public ModelAndView beikaifada(@RequestParam String operation,@RequestParam String state) {
        System.out.println("被开发打...");
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }


        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);

        return view;
    }

    @GetMapping("/yangshangchenggong")
    public ModelAndView yangshangchenggong(@RequestParam String operation,@RequestParam String state) {
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }


        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);

        return view;
    }

    @GetMapping("/yangshangshibai")
    public ModelAndView yangshangshibai(@RequestParam String operation,@RequestParam String state) {
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }


        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);

        return view;
    }

    @GetMapping("/lingdaobumanyiduini")
    public ModelAndView lingdaobumanyiduini(@RequestParam String operation,@RequestParam String state) {
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }


        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);

        return view;
    }

    @GetMapping("/yangshangchenggonggaixuqiuchenggong")
    public ModelAndView yangshangchenggonggaixuqiuchenggong(@RequestParam String operation,@RequestParam String state) {
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }


        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);

        return view;
    }

    @GetMapping("/gaixuqiuchenggong")
    public ModelAndView gaixuqiuchenggong(@RequestParam String operation,@RequestParam String state) {
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }


        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);

        return view;
    }

    @GetMapping("/lingdaobumanyi")
    public ModelAndView lingdaobumanyi(@RequestParam String operation,@RequestParam String state) {
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }


        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);
        return view;
    }

    @GetMapping("/gaixuqiu")
    public ModelAndView gaixuqiu(@RequestParam String operation,@RequestParam String state) {
        System.out.println("被开发打...");
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }


        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);

        return view;
    }

    @GetMapping("/siwang")
    public ModelAndView siwang(@RequestParam String operation,@RequestParam String state) {
        ArrayList<OperationDto> dtos = new ArrayList<>();

        ModelAndView view = new ModelAndView();
        view.setViewName("index");
        Map<String, List<OperationDto>> dataSource = util.init();

        List<OperationDto> list = dataSource.get(state);
        for (int i = 0; i < list.size(); i++) {
            OperationDto operationDto = list.get(i);
            operationDto.setName(operationMap.get(list.get(i).getCode()));
            operationDto.setUrl("http://localhost:8080/"+list.get(i).getCode()+"?operation="+list.get(i).getCode()+"&state="+operationDto.getTo());
            dtos.add(operationDto);
        }
        view.addObject("state",stateMap.get(state));
        view.addObject("operationList",dtos);
        return view;
    }
}

公司的状态机也是通过这种xml形式实现的,其实后来想想也可以通过枚举类实现。核心思想不变,只是换了实现方式而已。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值