JavaScript设计模式中的状态模式

Posted 三水草肃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript设计模式中的状态模式相关的知识,希望对你有一定的参考价值。

状态模式

状态模式的关键是区分事物内部的状态,事物内部状态的改变往往会带来事物的行为改变

状态模式的优缺点

  1. 优点
    1. 把状态和行为封装成单独的类,独立而互不影响,也容易新增状态和转换。符合开放封闭原则。
    2. 避免 Context 增加过多的类,状态切换的逻辑被分布在状态类中。
  2. 缺点
    1. 如果会定义许多状态类,逻辑分散,状态逻辑梳理复杂。

状态模式的性能优化点

  1. 主要是 state 状态对象的创建和销毁

    1. state 被需要才创建。 如果对象比较庞大,可以使用这个节省内存,避免一些不会用到的对象及时回收。
    2. state 一开始就创建所有的状态对象,并且始终不销毁。状态改变很频繁的时候使用
  2. 本例子中(upload2.html)每个 Context 都创建一个 state 对象,实际上 Context 可以共享一个 state 对象,也是享元模式的应用场景之一。

如何做好状态模式

  1. 状态模式先定义状态,并把所有的状态都封装成单独的对象,统一去维护。健壮性 + 开放封闭
  2. Light 也被称为上下文 Context,随后在 Light 的构造函数中,我们创建每一种状态类的实例对象,Context 将持有这些状态对象的引用,以便把请求交给状态对象。
/**
 * 初始状态模式
 * 1. 电灯,电灯开着,按下开关,会切换到关闭状态。电灯关着,按下开关,会切换到开启状态。
 * 2. light是从Light类创建出来。
 * 3. light对象也要传入状态类的构造函数,以便调用light中的方法
 */

const Light = function () 
  this.state = "off"; // 设置灯泡的初始状态
  this.button = null; // 电灯开关按钮
;

// 按钮初始化,创建一个真实button节点
Light.prototype.init = function () 
  const button = document.createElement("button");
  const self = this;

  button.innerHTML = "开关";
  this.button = document.body.appendChild(button);
  console.log(this.button);
  this.button.onclick = function () 
    self.buttonWasPressed();
  ;
;

// 开关被按下,程序会调用self.buttonWasPressed方法,开关按下之后的所有行为,都会被封装在这个方法里。
Light.prototype.buttonWasPressed = function () 
  if (this.state === "off") 
    this.state = "on";
    console.log("开灯");
   else 
    this.state = "off";
    console.log("关灯");
  
;

const light = new Light();
light.init();

/**
 * 以上代码违法开放封闭原则,每次新增状态都需要在buttonWaspressed里进行修改,会改动其余的代码。
 * 状态难以察觉,没有一个对象统一维护所有的状态
 * 大量使用if else让代码不具备健壮性
 */

/**
 * 每次状态改变,状态对象就会给Light传下一次要执行的状态对象。
 */
// off
const OffLight = function (light) 
  this.light = light;
;
OffLight.prototype.buttonWasPressed = function () 
  console.log("弱光");
  this.light.setState(this.light.weakLightState); // 切换状态
;

const WeakLight = function (light) 
  this.light = light;
;
WeakLight.prototype.buttonWasPressed = function () 
  console.log("强光");
  this.light.setState(this.light.strongLightState); // 切换状态
;
const StrongLight = function (light) 
  this.light = light;
;
StrongLight.prototype.buttonWasPressed = function () 
  console.log("关灯");
  this.light.setState(this.light.offLightState); // 切换状态
;

const Light2 = function () 
  this.offLightState = new OffLight(this);
  this.weakLightState = new WeakLight(this);
  this.strongLightState = new StrongLight(this);
  this.button = null;
;

// 通过self.currentState.buttonWasPressed()将请求委托给当前持有的状态对象去执行
Light2.prototype.init = function () 
  debugger;
  const button = document.createElement("button");
  const self = this;
  this.button = document.body.appendChild(button);
  this.button.innerHTML = "开关2";
  this.currentState = this.offLightState; // 初始状态
  this.button.onclick = function () 
    self.currentState.buttonWasPressed();
  ;
;
Light2.prototype.setState = function (newState) 
  this.currentState = newState;
;

const light2 = new Light2();
light2.init();

状态模式和策略模式的关系

  1. 相同点:

    1. 他们都封装了一系列的算法或者行为,他们的类图看起来一样。
    2. 都有一个上下文、一些策略或者状态类,上下文把请求委托给这些类来执行。
  2. 不同点:

    1. 策略模式的各个策略类是平等又平行的,他们之间没有任何联系,所以客户必须熟知这些策略类的作用,以便客户可以随时主动切换算法;
    2. 状态模式对应的行为是已经封装好的,状态之间的切换也早被规定好。改变行为是发生在状态模式内部,不需要了解这些细节。这也是状态模式的作用所在。

以上是关于JavaScript设计模式中的状态模式的主要内容,如果未能解决你的问题,请参考以下文章

状态模式全解析--JavaScript

08-开关与电灯:桥接模式

JavaScript中的设计模式:状态模式

JavaScript设计模式中的状态模式

JavaScript设计模式中的状态模式

JavaScript设计模式中的享元模式