背景

最近在做数据安全管控,涉及一个模块包含了很多状态(待发布、发布中、发布成功、发布失败、撤销、删除),看到这么多状态感觉头皮发麻啊,就想着有没有一种模式去解决这种问题,自然就找到了状态模式。

状态模式

程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移。


很明显我遇到的这个问题就很适合用状态模式去解决:

  • 1、状态有限,待发布、发布中、发布成功、发布失败、撤销、删除。
  • 2、存在状态的瞬间切换。比如:发布中 -> 发布成功;发布中 -> 发布失败。

具体实现

上下文

原始对象被称为上下文 (context), 它并不会自行实现所有行为, 而是会保存一个指向表示当前状态的状态对象的引用, 且将所有与状态相关的工作委派给该对象。

我个人的理解上下文就像是一个管理者,他负责管理状态,切换不同的状态去执行不同的业务。

public class PolicyContext {

  private PolicyState policyState;

  public Boolean updatePolicyStatus(String status, ExtraData extraData) {
    policyState.doAction(this, extraData);
    return Boolean.TRUE;
  }
}

状态

如需将上下文转换为另外一种状态, 则需将当前活动的状态对象替换为另外一个代表新状态的对象。 采用这种方式是有前提的: 所有状态类都必须遵循同样的接口, 而且上下文必须仅通过接口与这些对象进行交互。

状态很简单,其实像是一个抽象类,他是每一种状态都必须继承或者实现的类,这样上下文才可以对状态进行切换。

public interface PolicyState {

  /**
   * 具体业务实现方法
   * @param policyContext 策略上下文
   * @return
   */
  Boolean doAction(PolicyContext policyContext, ExtraData extraData);
}

状态具体实现

我举出的只是一个发布中的状态例子,其他的状态也和此类似。看伪代码可以发现,处于发布中状态的策略,其实还可能切换到发布成功或者发布失败状态。
但是,我并没有在此类中去具体实现发布成功或者发布失败的业务,个人觉得这也是状态策略的魅力所在点之一(模块式开发管理),不同的状态处理不同的业务,不存在业务交叉,这样以后无论你是增加一个状态还是删除一个状态,都不会对代码有很大的改动。

public class PolicyReleasingState implements PolicyState {

  @Autowired private PolicyService policyService;

  @Override
  public Boolean doAction(PolicyContext policyContext, ExtraData extraData) {
    System.out.println("策略发布中。。。。。。");

    // 1、 首先核验策略状态,只有处于待发布状态,才可以发布
    Policy policyInfo = policyService.getPolicyInfo(extraData.getPolicyId());
    String status = policyInfo.getStatus();
    if (StringUtils.equals(status, "待发布")) {
      // 2、 修改策略状态为发布中
      policyContext.setPolicyState(this);
      Boolean releaseSuccess = policyService.updatePolicyStatus("发布中");

      // 3、 发布成功,修改策略状态为成功,发布失败,修改策略状态为失败
      if (releaseSuccess) {
        policyContext.setPolicyState(new PolicyReleaseSuccessState());
        policyContext.updatePolicyStatus("发布成功", extraData);
      } else {
        policyContext.setPolicyState(new PolicyReleaseFailState());
        policyContext.updatePolicyStatus("发布失败", extraData);
      }
    } else {
      log.info("非法操作");
    }
    return Boolean.TRUE;
  }
}

状态模式 VS 策略模式

状态模式可能看上去与策略模式相似,但有一个关键性的不同——在状态模式中, 特定状态知道其他所有状态的存在, 且能触发从一个状态到另一个状态的转换; 策略则几乎完全不知道其他策略的存在。


个人理解状态具有属性性质,属性性质代表着可预见性,也就是我肯定知道我有多少个状态;而策略则不一样,策略不具备属性性质,他是一个单独的个体,每一个单独的个体都不知道其他的个体的作用(存在)。
举个例子,现在短信平台可以选择腾讯或者阿里,但是腾讯或者阿里不是短信的属性。假如项目中使用了这两个作为短信发送的渠道,就可以使用策略模式去管理。

Last modification:April 15, 2022
如果觉得我的文章对你有用,请随意赞赏