文章目录
一、状态模式介绍
状态模式描述的是行为导致对象的状态变更。例如,在某个审核流程中,审核人员在待审核列表
点击审核通过
,那么相应审核项的状态就由
待审核状态
变成了
审核通过状态
,审核人员在待审核列表
点击审核不通过
,那么相应审核项的状态就由
待审核状态
变成了
审核不通过状态
二、需求审批状态流转场景
本案例模拟一个普通的OA申请流程,假设一个需求从创建到完成需要经过多级审核。
1.审批流程
审批流程如下:
2.设计实现
状态枚举:
@Getter
public enum DemandState {
// 状态枚举
TOBE_CONFIRMED(10, "待确认"),
TOBE_APPLIED(20, "待申请"),
TOBE_AUDITED(30, "待审核"),
AUDIT_PASS(40, "审核通过"),
AUDIT_REFUSE(50, "审核驳回"),
RET_BACK(60, "退回");
private Integer state;
private String desc;
DemandState(Integer state, String desc) {
this.state = state;
this.desc = desc;
}
}
事件枚举:
@Getter
public enum EventType {
// 事件枚举
CONFIRM(10, "确认需求"),
COMMIT(20, "提交审核"),
AUDIT_PASS(30, "审核通过"),
AUDIT_REFUSE(40, "审核不通过"),
REFUSED_THEN_UPDATE(50, "提交修改"),
REFUSED_THEN_RET_BACK(60, "退回"),
NOT_CONFIRM(70, "退回"),
RET_BACK_THEN_UPDATE(80, "提交修改"),
;
private Integer type;
private String desc;
EventType(Integer type, String desc) {
this.type = type;
this.desc = desc;
}
}
对象实体:
@Data
public class Demand {
/**
* 对象唯一标识
*/
private Long id;
/**
* 对象当前状态
*/
private Integer state;
/**
* 其他的一些信息
*/
private String otherInfos;
}
上下文:
上下文中包含需要进行状态流转的对象以及对应的事件。
@Getter
@Setter
public class Context {
private Demand demand;
private Integer eventType;
}
状态流转:
@Getter
@AllArgsConstructor
public abstract class Transition {
/**
* 当前状态
*/
private final Integer currentState;
/**
* 下一个状态
*/
private final Integer nextState;
/**
* 创建状态流转
*/
public static Transition transition(DemandState currentState, DemandState nextState) {
return new Transition(currentState.getState(), nextState.getState());
}
}
事件:
事件在发生状态流转之前,可能会有一些前置和后置的操作,因此设计一个事件基类来提供这种扩展能力。
@Slf4j
@Getter
public abstract class Event {
/**
* 事件类型
*/
private final Integer eventType;
/**
* 状态流转
*/
private final Transition transition;
protected Event(EventType eventType, Transition transition) {
this.eventType = eventType.getType();
this.transition = transition;
}
/**
* 状态流转前操作
*/
public void beforeTransit(Context ctx) {
// 判断当前对象状态是否合法
if (!transition.getCurrentState().equals(ctx.getDemand().getState())) {
throw new IllegalArgumentException("需求当前状态[" + ctx.getDemand().getState() + "]不合法");
}
}
/**
* 状态流转
*/
public void transit(Context ctx) {
log.info("执行状态变更:{} -> {}", transition.getCurrentState(), transition.getNextState());
ctx.getDemand().setState(transition.getNextState());
}
/**
* 状态流转后操作
*/
public void postTransit(Context ctx) {
}
}
然后根据具体的时间定义出具体的事件类,这里给出几个:
/**
* 确认需求事件
*/
public class ConfirmEvent extends Event {
public ConfirmEvent() {
super(EventType.CONFIRM, Transition.transition(DemandState.TOBE_CONFIRMED, DemandState.TOBE_APPLIED));
}
}
/**
* 提交审核事件
*/
public class CommitEvent extends Event {
public CommitEvent() {
super(EventType.COMMIT, Transition.transition(DemandState.TOBE_APPLIED, DemandState.TOBE_AUDITED));
}
}
/**
* 审核通过事件
*/
public class AuditPassEvent extends Event {
public AuditPassEvent() {
super(EventType.AUDIT_PASS, Transition.transition(DemandState.TOBE_AUDITED, DemandState.AUDIT_PASS));
}
}
定义一个状态机,触发事件:
public class StateMachine {
public static void trigger(Context ctx) {
Event event = EventFactory.getEvent(ctx.getEventType());
if (event != null) {
event.beforeTransit(ctx);
event.transit(ctx);
event.postTransit(ctx);
}
}
public static class EventFactory {
private static final Map<Integer, Event> EVENT_MAP;
static {
EVENT_MAP = new HashMap<>();
// 这里需要引入org.reflections:reflections:0.10.2
Reflections reflections = new Reflections("com.example.study.dp.state.event");
Set<Class<? extends Event>> subTypesOfEvent = reflections.getSubTypesOf(Event.class);
subTypesOfEvent.forEach(subType->{
try {
Event event = subType.newInstance();
EVENT_MAP.put(event.getEventType(), event);
} catch (Exception e) {
}
});
}
public static Event getEvent(Integer eventType) {
return EVENT_MAP.get(eventType);
}
}
}
3.测试
public class Main {
public static Demand initDemand() {
Demand demand = new Demand();
demand.setId(1L);
demand.setState(DemandState.TOBE_CONFIRMED.getState());
return demand;
}
public static Context initContext(Integer eventType) {
Context context = new Context();
context.setDemand(initDemand());
context.setEventType(eventType);
return context;
}
public static void main(String[] args) {
// 需求确认事件
Context context = initContext(EventType.CONFIRM.getType());
StateMachine.trigger(context);
// 提交审核事件
context.setEventType(EventType.COMMIT.getType());
StateMachine.trigger(context);
// 再次提交审核,这里会报错
context.setEventType(EventType.COMMIT.getType());
StateMachine.trigger(context);
}
}
测试结果:
版权声明:本文为DiligentOrange原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。