状态模式

状态模式能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样

适用场景

  • 对象需要根据自身当前状态进行不同行为,同时状态的数量非常多且与状态相关的代码会频繁变更的话,可使用状态模式

  • 某个类需要根据成员变量的当前值改变自身行为,从而需要使用大量的条件语句时,可使用该模式

  • 相似状态和基于条件的状态机转换中存在许多重复代码时,可使用状态模式

优/缺点

优点:

  • 单一职责原则。将与特定状态相关的代码放在单独的类中。

  • 开闭原则。无需修改已有状态类和上下文就能引入新状态。

  • 通过消除臃肿的状态机条件语句简化上下文代码。

缺点:

  • 如果状态机只有很少的几个状态,或者很少发生改变,那么应用该模式可能会显得小题大作。

对比其他模式

  • 桥接模式、状态模式和策略模式(在某种程度上包括适配器模式)模式的接口非常相似。 都是基于组合模式 -- 将工作委派给其他对象

  • 状态可被视为策略的扩展。两者都基于组合机制。 策略使得这些对象相互之间完全独立,它们不知道其他对象的存在。 状态模式没有限制具体状态之间的依赖,且允许它们自行改变在不同情景下的状态。

实现示例

class AudioPlayer {
  private state: AudioPlayerState;
  private ui: any;
  private volume: any;
  private playlist: any;
  private curSong: any;

  constructor() {
    this.state = new AudioPlayerState(this);
    this.ui = new UserInterface();
    this.ui.lockButton.onClick(this.clickLock);
    this.ui.playButton.onClick(this.clickPlay);
    this.ui.nextButton.onClick(this.clickNext);
    this.ui.prevButton.onClick(this.clickPrevious);
  }

  changeState(state: AudioPlayerState) {
    this.state = state;
  }

  clickLock() {
    this.state.clickLock();
  }
  clickPlay() {
    this.state.clickPlay();
  }
  clickNext() {
    this.state.clickNext();
  }
  clickPrevious() {
    this.state.clickPrevious();
  }

  //   startPlayback() {}
  //   stopPlayback() {}
  //   nextSong() {}
  //   previousSong() {}
  //   fastForward(time) {}
  //   rewind(time) {}
}

abstract class AudioPlayerState {
  constructor(player) {
    this.player = player;
  }

  clickLock(): void;
  clickPlay(): void;
  clickNext(): void;
  clickPrevious(): void;
}

class LockedState extends State {
  clickLock() {
    if (player.playing) {
      player.changeState(new PlayingState(player));
    } else {
      player.changeState(new ReadyState(player));
    }
  }
  clickPlay(): void {
    /*undo anything*/
  }
  clickNext(): void {
    /*undo anything*/
  }
  clickPrevious(): void {
    /*undo anything*/
  }
}

class ReadyState extends State {}
class PlayingState extends State {}

最后更新于