TypeScript | 设计模式17 -状态模式

807 阅读2分钟

这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战

状态模式

对有状态的对象,把复杂的判断逻辑提取到不同的状态对象中,允许状态对象在其内部状态发生 变化时改变其行为。

模式结构

  • 上下文,Context 定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换
  • 抽象状态,定义接口,声明上下文中特定状态对应的方法。, 可以一个或多个的行为
  • 具体状态,实现抽象状态所对应的行为,并且在需要的情况下进行状态切换
// 上下文类,其中包含状态
class Context {
  private state: State;
  constructor(state: State) {
    this.state = state;
  }
​
  // 对请求做处理,当状态变化时允许改变对象
  handler() {
    this.state.handle(this);
  }
}
​
// 抽象状态类
interface State {
  context: Context;
  handle(context: Context): void;
}
​
// 
class AState implements State {
  context: Context;
  handle(context: Context): void {
    console.log("当前状态1");
    // 状态改变时需要改变其行为,此处将行为改为状态2
    this.context = new Context(new BState());
  }
}
​
class BState implements State {
  context: Context;
  handle(context: Context): void {
    console.log("当前状态2");
  }
}
​
(() => {
  const hd1 = new AState();
  const ctx = new Context(hd1);
  ctx.handler(); // 执行第一次后状态切换成状态2
  ctx.handler();// 执行的是状态2 的
})();
​

Context类中保存了对具体状态的引用,且支持其根据不同对象进行切换。State类中存储对于Context对象的反向引用。 然后可以通过该引用从上下文处获取所需信息, 并且能触发状态转移。

主要优点

  • 将与特定状态相关的代码放在单独的类中,符合单一职责原理
  • 将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
  • 引入新状态时无需修改已有状态类的上下文
  • 通过消除臃肿的状态机条件语句简化上下文代码

主要缺点

  • 如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作。
  • 状态模式的使用必然会增加系统的类与对象的个数。

适用场景

  • 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
  • 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。
  • 当相似状态和基于条件的状态机转换中存在许多重复代码时,可使用状态模式。
  • 如果某个类需要根据成员变量的当前值改变自身行为,从而需要使用大量的条件语句时,可使用该模式

\