策略枚举的用法一:状态流转

2,049 阅读4分钟

说明

本文只对策略枚举可以使用的场景进行说明,不做其他介绍。提供额外的实现思路。

状态流转

在开发过程中,难免会遇到状态之间的流转,如何方便维护并且能够一目了然的知道状态之间的流转呢? 例如: 在这里插入图片描述 上图可以看出,我们有状态组:黄色框的内容;操作组:连接线上的内容。 就可以使用一个状态枚举来包装

package com.strategy.enums;

/**
 * 单据状态
 */
public enum StatusEnum {

    /** 已提报 */
    HAD_CREATE(1, "已新建"),

    /** 已提报 */
    HAD_SUBMIT(2, "已提报") ,

    /** 已审核" */
    HAD_AUDIT(3, "已审核") ,

    /** 已退回 */
    HAD_BACK(4, "已退回"),

    /** 已拒绝 */
    HAD_REJECT(5, "已拒绝"),

    /** 已生成结算 */
    HAD_USE(6, "已生成结算"),

    /** 已关闭 */
    HAD_CLOSE(7, "已关闭");
    
    /** 枚举值 */
    private int index;

    /** 枚举描述 */
    private String name;

    StatusEnum(int index, String name) {
        this.index = index;
        this.name = name;
    }

    public int getIndex() {
        return index;
    }

    public String getName() {
        return name;
    }

}

如何改造成策略枚举呢,加上操作(方法)与绑定(重写)。

package com.strategy.enums;

/**
 * 单据状态
 */
public enum StatusEnum {

    /** 已提报 */
    HAD_CREATE(1, "已新建") {
        @Override
        public StatusEnum create() {
            return HAD_CREATE;
        }
        @Override
        public StatusEnum save() {
            return HAD_CREATE;
        }
        @Override
        public StatusEnum submit() {
            return HAD_SUBMIT;
        }
        @Override
        public StatusEnum close() {
            return HAD_CLOSE;
        }
    },

    /** 已提报 */
    HAD_SUBMIT(2, "已提报") {
        @Override
        public StatusEnum pass() {
            return HAD_AUDIT;
        }
        @Override
        public StatusEnum back() {
            return HAD_BACK;
        }
        @Override
        public StatusEnum reject() {
            return HAD_REJECT;
        }
    },

    /** 已审核" */
    HAD_AUDIT(3, "已审核") {
        @Override
        public StatusEnum used() {
            return HAD_USE;
        }
    },

    /** 已退回 */
    HAD_BACK(4, "已退回") {
        @Override
        public StatusEnum save() {
            return HAD_BACK;
        }
        @Override
        public StatusEnum submit() {
            return HAD_SUBMIT;
        }
        @Override
        public StatusEnum close() {
            return HAD_CLOSE;
        }
    },

    /** 已拒绝 */
    HAD_REJECT(5, "已拒绝") {
    },

    /** 已使用 */
    HAD_USE(6, "已使用") {
    },

    /** 已关闭 */
    HAD_CLOSE(7, "已关闭") {
    };

    /** 枚举值 */
    private int index;

    /** 枚举描述 */
    private String name;

    /** 创建 */
    public StatusEnum create() {
        throw new RuntimeException("当前状态【" + this.getName() + "】不允许执行【创建】操作");
    }

    /** 暂存 */
    public StatusEnum save() {
        throw new RuntimeException("当前状态【" + this.getName() + "】不允许执行【暂存】操作");
    }

    /** 提报 */
    public StatusEnum submit() {
        throw new RuntimeException("当前状态【" + this.getName() + "】不允许执行【提报】操作");
    }

    /** 通过 */
    public StatusEnum pass() {
        throw new RuntimeException("当前状态【" + this.getName() + "】不允许执行【通过】操作");
    }

    /** 驳回 */
    public StatusEnum back() {
        throw new RuntimeException("当前状态【" + this.getName() + "】不允许执行【驳回】操作");
    }

    /** 拒绝 */
    public StatusEnum reject() {
        throw new RuntimeException("当前状态【" + this.getName() + "】不允许执行【拒绝】操作");
    }

    /** 使用 */
    public StatusEnum used() {
        throw new RuntimeException("当前状态【" + this.getName() + "】不允许执行【使用】操作");
    }

    /** 关闭 */
    public StatusEnum close() {
        throw new RuntimeException("当前状态【" + this.getName() + "】不允许执行【关闭】操作");
    }

    /** 使用的重点方法 */
    public static StatusEnum valueOf(Integer index) {
        if (index == null) {
            return null;
        }
        for (StatusEnum modeEnum : StatusEnum.values()) {
            if (index == modeEnum.getIndex()) {
                return modeEnum;
            }
        }
        return null;
    }
    
    StatusEnum(int index, String name) {
        this.index = index;
        this.name = name;
    }

    public int getIndex() {
        return index;
    }

    public String getName() {
        return name;
    }

}

以上,就实现了策略枚举,一个类实现了流程图的完整状态流转。 流程图已经准备好了,那要如何使用呢?很简单,只要一句话即可。 当我们修改数据状态的时候,首先需要从库中获取该数据的原始状态,已经知道我们当前的请求操作【按钮、方法】是什么。所以两个决定因数已经有了,就可以进行操作

package com.strategy.enums;

import java.util.ArrayList;
import java.util.List;

/**
 * 单据状态 测试类
 */
public class StatusEnumMainTest {

    public static void main(String[] args) {
        new StatusEnumMainTest().test();
    }

    private void test() {
        // 假设从数据库中获取了改数据的状态
        List<StatusEnumTest> list = getInitList();
        // 已新建数据进行提报(成功)
        StatusEnumTest statusEnumTest1 = getStatusEnumTest(1L, list);
        System.out.println("修改前的数据:" + statusEnumTest1.toString());
        statusEnumTest1.setStatus(StatusEnum.valueOf(statusEnumTest1.getStatus()).submit().getIndex());
        System.out.println("修改后的数据:" + statusEnumTest1.toString());
        // 已关闭数据进行修改(失败)
        StatusEnumTest statusEnumTest7 = getStatusEnumTest(7L, list);
        System.out.println("关闭前的数据:" + statusEnumTest7.toString());
        statusEnumTest1.setStatus(StatusEnum.valueOf(statusEnumTest7.getStatus()).save().getIndex());
        System.out.println("关闭后的数据:" + statusEnumTest7.toString());
    }

    private StatusEnumTest getStatusEnumTest(Long id, List<StatusEnumTest> list) {
        for (StatusEnumTest data : list) {
            if (id.equals(data.getId())) {
                return data;
            }
        }
        return null;
    }

    private List<StatusEnumTest> getInitList() {
        List<StatusEnumTest> list = new ArrayList<StatusEnumTest>();
        list.add(new StatusEnumTest(1L, 1, "这是已新建数据"));
        list.add(new StatusEnumTest(2L, 2, "这是已提报数据"));
        list.add(new StatusEnumTest(3L, 3, "这是已审核数据"));
        list.add(new StatusEnumTest(4L, 4, "这是已退回数据"));
        list.add(new StatusEnumTest(5L, 5, "这是已拒绝数据"));
        list.add(new StatusEnumTest(6L, 6, "这是已使用数据"));
        list.add(new StatusEnumTest(7L, 7, "这是已关闭数据"));
        return list;
    }

    private class StatusEnumTest {
        private Long id;
        private Integer status;
        private String other;

        public StatusEnumTest(Long id, Integer status, String other) {
            this.id = id;
            this.status = status;
            this.other = other;
        }

        public Long getId() {
            return id;
        }

        public Integer getStatus() {
            return status;
        }

        public void setStatus(Integer status) {
            this.status = status;
        }

        public String getOther() {
            return other;
        }

        @Override
        public String toString() {
            return "StatusEnumTest{" + "id=" + id + ", status=" + status + ", other='" + other + '\'' + '}';
        }
    }

}

运行结果如下

修改前的数据:StatusEnumTest{id=1, status=1, statusName=已新建, other='这是已新建数据'}
修改后的数据:StatusEnumTest{id=1, status=2, statusName=已提报, other='这是已新建数据'}
关闭前的数据:StatusEnumTest{id=7, status=7, statusName=已关闭, other='这是已关闭数据'}
java.lang.RuntimeException: 当前状态【已关闭】不允许执行【暂存】操作
	at com.strategy.enums.StatusEnum.save(StatusEnum.java:100)
	at com.strategy.enums.StatusEnumMainTest.test(StatusEnumMainTest.java:26)
	at com.strategy.enums.StatusEnumMainTest.main(StatusEnumMainTest.java:12)

这样我们就能够使用代码来控制状态的流转。既能控制流程,也能获取下一个状态,一举两得。