# 状态模式

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

## 适用场景

* 对象需要根据自身当前状态进行不同行为，同时状态的数量非常多且与状态相关的代码会频繁变更的话，可使用状态模式
* 某个类需要根据成员变量的当前值改变自身行为，从而需要使用大量的条件语句时，可使用该模式
* 相似状态和基于条件的状态机转换中存在许多重复代码时，可使用状态模式

## 优/缺点

优点：

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

缺点：

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

## 对比其他模式

* 桥接模式、状态模式和策略模式（在某种程度上包括适配器模式）模式的接口非常相似。 都是基于组合模式 -- 将工作委派给其他对象
* 状态可被视为策略的扩展。两者都基于组合机制。 策略使得这些对象相互之间完全独立，它们不知道其他对象的存在。 状态模式没有限制具体状态之间的依赖，且允许它们自行改变在不同情景下的状态。

## 实现示例

```ts
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 {}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xyy94813.gitbook.io/x-note/she-ji-mo-shi/chang-jian-she-ji-mo-shi/state.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
