状态模式

简介: 状态模式

顽强的毅力可以征服世界上任何一座高峰。——狄更斯

我们在实现审核业务的时候,可能在没使用状态模式的时候,使用if else或者switch case进行操作

ruben说:我不能针对不同的状态写多个后端接口吗?

achao说:那你前端还是要使用if else去根据不同的状态调用不同的接口啊

我这里模拟一个简单的审核,真实项目中的业务将比这复杂

我们在用户提交审核后,状态应该是待审核

待审核时执行操作,如果用户提交的内容为空,则将状态更改为审核未通过

待审核时执行操作,如果用户提交的内容不为空,则将状态更改为审核已通过

审核未通过时,如果用户再次执行操作,提示重新提交审核

审核已通过时,如果用户再次执行操作,提示审核已通过

这里我们采用状态模式实现:

首先定义一个状态接口:

package com.ruben.state.example;
import java.util.Map;
/**
 * 审核状态公共接口
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/10/17 18:43
 */
public interface ApprovalStatus {
    String CONTENT = "content";
    String STATUS = "status";
    /**
     * 审核
     *
     * @param param 参数
     * @return 结果
     */
    Map<String, Object> execute(Map<String, Object> param);
    /**
     * 设置操作类
     *
     * @param executor 操作类
     */
    void setExecutor(ApprovalExecutor executor);
}


其中包含我们主要的审核操作以及设置操作类的方法,以及两个常量

这里的操作类下面会提到

然后是抽象类,包含我们共有方法,例如给状态设置操作类,这里将操作类设为protected,允许子类状态访问该操作类

package com.ruben.state.example;
/**
 * 抽象状态
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/10/17 18:49
 */
public abstract class BaseStatus implements ApprovalStatus {
    protected ApprovalExecutor executor;
    /**
     * 设置操作类
     *
     * @param executor 操作类
     */
    @Override
    public void setExecutor(ApprovalExecutor executor) {
        this.executor = executor;
    }
}

然后是实现各个状态:

待审核

package com.ruben.state.example;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
/**
 * 待审核
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/10/17 18:48
 */
public class WaitStatus extends BaseStatus {
    /**
     * 审核
     *
     * @param param 参数
     * @return 结果
     */
    @Override
    public Map<String, Object> execute(Map<String, Object> param) {
        boolean pass = Objects.nonNull(param.get(CONTENT));
        ApprovalStatus status;
        if (pass) {
            status = new PassStatus();
        } else {
            System.out.println("提交内容为空,审核未通过");
            status = new RejectStatus();
        }
        executor.changeStatus(status);
        return Collections.singletonMap(STATUS, status.getClass().getSimpleName());
    }
}


已通过:

package com.ruben.state.example;
import java.util.Collections;
import java.util.Map;
/**
 * 已通过
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/10/17 19:12
 */
public class PassStatus extends BaseStatus {
    /**
     * 审核
     *
     * @param param 参数
     * @return 结果
     */
    @Override
    public Map<String, Object> execute(Map<String, Object> param) {
        System.out.println("您已经通过审核了,不能进行操作啦!");
        return Collections.singletonMap(STATUS, this.getClass().getSimpleName());
    }
}

已拒绝:

package com.ruben.state.example;
import java.util.Collections;
import java.util.Map;
/**
 * 已拒绝
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/10/17 19:14
 */
public class RejectStatus extends BaseStatus {
    /**
     * 审核
     *
     * @param param 参数
     * @return 结果
     */
    @Override
    public Map<String, Object> execute(Map<String, Object> param) {
        System.out.println("您未通过审核,请重新提交审核!");
        return Collections.singletonMap(STATUS, this.getClass().getSimpleName());
    }
}

然后就是我们的操作类了

这里将状态接口作为成员变量

提供一个带参构造器,让我们初始具有一个状态

提供一个变更状态的方法,应对状态变更的情况,顺便将我们的操作类传递给对应的状态

提供一个审核方法,该方法就是我们在客户端实际操作的方法,它会根据不同的状态(实际的状态实现类)调用对应的实现

操作类避免了直接操作对应的方法,减少了我们代码中的if else/switch case

package com.ruben.state.example;
import java.util.Map;
/**
 * 审核操作类
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/10/17 18:52
 */
public class ApprovalExecutor {
    private ApprovalStatus status;
    public ApprovalExecutor(ApprovalStatus status) {
        this.status = status;
    }
    /**
     * 变更状态
     *
     * @param status 状态
     */
    public void changeStatus(ApprovalStatus status) {
        this.status = status;
        status.setExecutor(this);
    }
    /**
     * 审核
     *
     * @param param 参数
     * @return 结果
     */
    public Map<String, Object> execute(Map<String, Object> param) {
        return status.execute(param);
    }
}

最后是运行方法:

package com.ruben.state.example;
import java.util.HashMap;
import java.util.Map;
/**
 * 审核应用
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/10/17 19:15
 */
public class ApprovalApplication {
    public static void main(String[] args) {
        Map<String, Object> param = new HashMap<>(1 << 2);
        System.out.println("用户提交审核");
        WaitStatus waitStatus = new WaitStatus();
        ApprovalExecutor executor = new ApprovalExecutor(waitStatus);
        waitStatus.setExecutor(executor);
        Map<String, Object> result = executor.execute(param);
        System.out.println(result);
        System.out.println("再次尝试提交");
        executor.execute(param);
        System.out.println("用户填写内容");
        param.put(ApprovalStatus.CONTENT, "666");
        System.out.println("用户再次提交审核");
        executor.changeStatus(waitStatus);
        result = executor.execute(param);
        System.out.println(result);
        executor.execute(param);
    }
}

状态模式优点

  • 单一职责原则。 将与特定状态相关的代码放在单独的类中。
  • 开闭原则。 无需修改已有状态类和上下文就能引入新状态。
  • 通过消除臃肿的状态机条件语句简化上下文代码。

状态模式缺点

  • 如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作。
相关文章
|
22天前
|
设计模式 算法
状态模式和策略模式有什么区别
状态模式和策略模式有什么区别
13 1
|
5月前
行为型 状态模式
行为型 状态模式
17 0
|
10月前
状态模式的总结
状态模式的总结
|
11月前
|
设计模式 JavaScript
关于状态模式我所知道的
关于状态模式我所知道的
47 0
|
设计模式 算法 Java
状态模式和策略模式的区别与联系
UML 状态模式是策略模式的孪生兄弟,是因为它们的UML图是一样的。但意图却完全不一样,策略模式是让用户指定更换的策略算法,而状态模式是状态在满足一定条件下的自动更换,用户无法指定状态,最多只能设置初始状态。
|
设计模式
我学会了,状态模式
状态模式属于行为型模式,这个类型的设计模式总结出了 类、对象之间的经典交互方式,将类、对象的行为和使用解耦了,花式的去使用对象的行为来完成特定场景下的功能。
86 0
我学会了,状态模式
|
设计模式
|
uml
状态模式与备忘录模式(1)
状态模式与备忘录模式(1)
75 0
状态模式与备忘录模式(1)
|
存储 Java Spring
状态模式与备忘录模式(3)
状态模式与备忘录模式(3)
117 0
状态模式与备忘录模式(3)
|
存储 程序员 开发工具
状态模式与备忘录模式(2)
状态模式与备忘录模式(2)
119 0
状态模式与备忘录模式(2)