设计模式之状态模式

1.定义

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

允许状态对象在其内部状态发生改变时改变其行为。使得这个对象看起来已经被修改了。

不同的状态的对象会产生不同的行为。用来解耦状态间的依赖。

2.场景

1.游戏中角色的状态改变,不同状态下的攻击模式或者行为不同。

2.工作流中,状态的审批流程。

3.案例1

1.模拟游戏中角色状态

在英雄联盟中的有的游戏有两种形态,或者是认为两种模式。当前切换不同模式时,技能会发生变化。

在这里就定义出一个技能接口,然后分普通状态和狂暴状态。

2.接口定义

//技能接口已经在之前策略模式中定义过,这里直接拿来用
public interface SkillState extends Skill{

}

3.定义实现类

@AllArgsConstructor
@NoArgsConstructor
public class NormalState implements SkillState{

    private Hero hero;

    /**
     * 用于注册唯一标识
     *
     * @return
     */
    @Override
    public String getNo() {
        return "NormalState";
    }

    @Override
    public String Q() {
        return "电能震荡";
    }

    @Override
    public String W() {
        return "超能电荷";
    }

    @Override
    public String E() {
        return "速之门";
    }

    @Override
    public String R() {
        hero.changeStatus(new CrazyState(hero));
        return "墨丘利之炮切换至墨丘利之锤";
    }
}


@AllArgsConstructor
@NoArgsConstructor
public class CrazyState implements SkillState{

    private Hero hero;

    /**
     * 用于注册唯一标识
     *
     * @return
     */
    @Override
    public String getNo() {
        return "CrazyState";
    }

    @Override
    public String Q() {
        return "苍穹之跃";
    }

    @Override
    public String W() {
        return "闪电领域";
    }

    @Override
    public String E() {
        return "雷霆一击加";
    }

    @Override
    public String R() {
        //切换状态
        hero.changeStatus(new NormalState(hero));
        return "墨丘利之锤切换至墨丘利之炮";
    }
}

3.定义上下文管理器

public class Hero implements Skill {

    /**
     * 英雄名称
     */
    private String name;


    /**
     * 英雄技能状态
     */
    private SkillState skillState;

    public Hero(){
        //默认普通形态
        this.skillState = new NormalState(this);
        //默认英雄
        this.name = "Jayce";
    }

    public SkillState getStatus(){
        return this.skillState;
    }

    public void changeStatus(SkillState skillState){
        this.skillState = skillState;
    }

    /**
     * 用于注册唯一标识
     *
     * @return
     */
    @Override
    public String getNo() {
        return this.name+skillState.getNo();
    }

    @Override
    public String Q() {
        return skillState.Q();
    }

    @Override
    public String W() {
        return skillState.W();
    }

    @Override
    public String E() {
        return skillState.E();
    }

    @Override
    public String R() {
        return skillState.R();
    }

}

4.测试

public class TestApi {

    public static void main(String[] args) {
        Hero Jayce = new Hero();

        //模拟杰斯连招 炮形态:QEW + 锤形态:Q+W+E
        System.out.println(Jayce.Q());
        System.out.println(Jayce.E());
        System.out.println(Jayce.W());
        System.out.println(Jayce.R());
        System.out.println(Jayce.Q());
        System.out.println(Jayce.W());
        System.out.println(Jayce.E());

    }
}

电能震荡
速之门
超能电荷
墨丘利之炮切换至墨丘利之锤
苍穹之跃
闪电领域
雷霆一击加

4.案例2:

1.模拟审核流程场景

审核流程:1创建编辑、2待审核、3审核中、4审核拒绝(可以撤审到编辑状态)、5审核关闭

定义状态抽象类

public abstract class State {

    /**
     * 提交审核
     *
     * @param flowId    流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    public abstract Result submit(String flowId, Enum<Status> currentStatus);

    /**
     * 审核通过
     *
     * @param flowId    流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    public abstract Result checkPass(String flowId, Enum<Status> currentStatus);

    /**
     * 审核拒绝
     *
     * @param flowId    流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    public abstract Result checkRefuse(String flowId, Enum<Status> currentStatus);

    /**
     * 撤审撤销
     *
     * @param flowId    流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    public abstract Result checkRevoke(String flowId, Enum<Status> currentStatus);

    /**
     * 审核完成
     *
     * @param flowId    流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    public abstract Result finish(String flowId, Enum<Status> currentStatus);

}


public enum Status {

    // 1创建编辑、2待审核、3审核中、4审核拒绝(可以撤审到编辑状态)、5审核关闭
    Editing, Check, Pass, Refuse, Finish

}

2.定义实现类

根据不同的状态去判断所能做的操作,后面几种状态类似,这里就直接省略了。

public class CheckState extends State{
    /**
     * 提交审核
     *
     * @param flowId        流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    @Override
    public Result submit(String flowId, Enum<Status> currentStatus) {
        return new Result("0001","不可重复提交任务!");
    }

    /**
     * 审核通过
     *
     * @param flowId        流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    @Override
    public Result checkPass(String flowId, Enum<Status> currentStatus) {
        TaskService.execStatus(flowId, currentStatus, Status.Pass);
        return new Result("0000","审核通过");
    }

    /**
     * 审核拒绝
     *
     * @param flowId        流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    @Override
    public Result checkRefuse(String flowId, Enum<Status> currentStatus) {
        TaskService.execStatus(flowId, currentStatus, Status.Pass);
        return new Result("0000","审核不通过");
    }

    /**
     * 撤审撤销
     *  退回到编辑状态
     * @param flowId        流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    @Override
    public Result checkRevoke(String flowId, Enum<Status> currentStatus) {
        TaskService.execStatus(flowId, currentStatus, Status.Editing);
        return new Result("0000","审核撤回到编辑状态");
    }

    /**
     * 审核完成
     *
     * @param flowId        流程ID
     * @param currentStatus 当前状态
     * @return 执行结果
     */
    @Override
    public Result finish(String flowId, Enum<Status> currentStatus) {
        return new Result("0001", "审核中不可完成审核");
    }
}

3.状态处理器

public class StateHandler {

    private Map<Enum<Status>, State> stateMap = new ConcurrentHashMap<Enum<Status>, State>();

    public StateHandler() {
        stateMap.put(Status.Check, new CheckState());     // 待审核
        stateMap.put(Status.Finish, new FinishState());     // 已关闭
        stateMap.put(Status.Editing, new EditingState()); // 编辑中
        stateMap.put(Status.Pass, new PassState());       // 审核通过
        stateMap.put(Status.Refuse, new RefuseState());   // 审核拒绝
    }

    public Result submit(String activityId, Enum<Status> currentStatus) {
        return stateMap.get(currentStatus).submit(activityId, currentStatus);
    }

    public Result checkPass(String activityId, Enum<Status> currentStatus) {
        return stateMap.get(currentStatus).checkPass(activityId, currentStatus);
    }

    public Result checkRefuse(String activityId, Enum<Status> currentStatus) {
        return stateMap.get(currentStatus).checkRefuse(activityId, currentStatus);
    }

    public Result checkRevoke(String activityId, Enum<Status> currentStatus) {
        return stateMap.get(currentStatus).checkRevoke(activityId, currentStatus);
    }

    public Result finish(String activityId, Enum<Status> currentStatus) {
        return stateMap.get(currentStatus).finish(activityId, currentStatus);
    }


}

4.模拟流程

public class TaskService {

    /**
     * 模拟数据库状态
     */
    private static Map<String, Enum<Status>> statusMap = new ConcurrentHashMap<String, Enum<Status>>();

    /**
     * 初始化任务流程
     * @param flowId
     * @param status
     */
    public static void init(String flowId, Enum<Status> status) {
        TaskInfo task = new TaskInfo();
        task.setFlowId(flowId);
        task.setTaskName("请假审批流程");
        task.setStatus(status);
        task.setCreateDate(new Date());
        statusMap.put(flowId, status);
    }


    /**
     * 查询当前状态
     *
     * @param flowId 活动ID
     * @return 查询结果
     */
    public static Enum<Status> queryActivityStatus(String flowId) {
        return statusMap.get(flowId);
    }

    /**
     * 执行状态变更
     *
     * @param flowId   流程ID
     * @param beforeStatus 变更前状态
     * @param afterStatus  变更后状态 b
     */
    public static synchronized void execStatus(String flowId, Enum<Status> beforeStatus, Enum<Status> afterStatus) {
        if (!beforeStatus.equals(statusMap.get(flowId))) return;
        statusMap.put(flowId, afterStatus);
    }

}

5.测试

public class TestApi {

    public static void main(String[] args) {
            String flowId = "100001";
            TaskService.init(flowId, Status.Editing);
            StateHandler stateHandler = new StateHandler();
            Result result = stateHandler.submit(flowId, Status.Editing);
            System.out.println(JSONUtil.toJsonStr(result));
            System.out.println(TaskService.queryActivityStatus(flowId));
    }
}

{"code":"0000","status":"任务提交成功!"}
Check

5.总结

状态模式和策略有点类似,不同的就是策略中每个策略都是完全独立的。而状态模式没有限制状态之间的依赖,可以互相转变,也可以独立。

代码地址:GitHub - qianzzbatt/java-design-patterns at 514472e0e925b8da956240e16144419415823871

参考文章:

状态设计模式

重学 Java 设计模式:实战状态模式「模拟系统营销活动,状态流程审核发布上线场景」 | bugstack 虫洞栈

https://blog.csdn.net/d303577562/article/details/118578336

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值