设计模式之状态模式

  • Post author:
  • Post category:其他





一、状态模式介绍


状态模式描述的是行为导致对象的状态变更。例如,在某个审核流程中,审核人员在待审核列表

点击审核通过

,那么相应审核项的状态就由

待审核状态

变成了

审核通过状态

,审核人员在待审核列表

点击审核不通过

,那么相应审核项的状态就由

待审核状态

变成了

审核不通过状态



二、需求审批状态流转场景


本案例模拟一个普通的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 版权协议,转载请附上原文出处链接和本声明。