首頁 web前端 js教程 學習JavaScript設計模式之狀態模式_javascript技巧

學習JavaScript設計模式之狀態模式_javascript技巧

May 16, 2016 pm 03:20 PM
javascript 狀態模式 設計模式

狀態模式的關鍵是區分事物內部的狀態,事物內部狀態的改變往往會帶來事物的行為改變。

當電燈開著,此時按下開關,電燈會切換到關閉狀態;再按一次開關,電燈又會被打開。同一個開關在不同的狀態下,表現出來的行為是不一樣的。

一、有限狀態機

  • 狀態總數(state)是有限的。
  • 任一時刻,只處在一種狀態之中。
  • 在某種條件下,會從一種狀態轉變(transition)到另一種狀態。

允許一個物件在其內部狀態改變時改變它的行為,而物件看起來似乎修改了它的類別。
解釋:
(1)將狀態封裝成獨立的類別,並將請求委託給目前的狀態對象,當對象的內部狀態改變時,會帶來不同的行為變化。
(2)使用的對象,在不同的狀態下具有截然不同的行為(委託效果)

談到封裝,一般優先考慮封裝物件的行為,而不是物件的狀態。
但在狀態模式中剛好相反,狀態模式的關鍵是把事物的每種狀態都封裝成單獨的類別。

二、範例

點燈程式 (低光源 –> 強光 –> 關燈)循環

// 关灯
var OffLightState = function(light) {
  this.light = light;
};
// 弱光
var OffLightState = function(light) {
  this.light = light;
};
// 强光
var StrongLightState = function(light) {
  this.light = light;
};

var Light = function(){
  /* 开关状态 */
  this.offLight = new OffLightState(this);
  this.weakLight = new WeakLightState(this);
  this.strongLight = new StrongLightState(this);
  /* 快关按钮 */
  this.button = null;
};
Light.prototype.init = function() {
  var button = document.createElement("button"),
    self = this;
  this.button = document.body.appendChild(button);
  this.button.innerHTML = '开关';
  this.currentState = this.offLight;
  this.button.click = function() {
    self.currentState.buttonWasPressed();
  }
};
// 让抽象父类的抽象方法直接抛出一个异常(避免状态子类未实现buttonWasPressed方法)
Light.prototype.buttonWasPressed = function() {
  throw new Error("父类的buttonWasPressed方法必须被重写");
};
Light.prototype.setState = function(newState) {
  this.currentState = newState;
};

/* 关灯 */
OffLightState.prototype = new Light(); // 继承抽象类
OffLightState.prototype.buttonWasPressed = function() {
  console.log("关灯!");
  this.light.setState(this.light.weakLight);
}
/* 弱光 */
WeakLightState.prototype = new Light();
WeakLightState.prototype.buttonWasPressed = function() {
  console.log("弱光!");
  this.light.setState(this.light.strongLight);
};
/* 强光 */
StrongLightState.prototype = new Light();
StrongLightState.prototype.buttonWasPressed = function() {
  console.log("强光!");
  this.light.setState(this.light.offLight);
};

登入後複製

PS:說明補充
必須先把OffLightState、WeakLightState、StrongLightState構造函數提前。

new A("a");
var A = function(a) {
  console.log(a)
}

new B("b");
function B(b) {
  console.log(b);
}

登入後複製

函數宣告會被提升到普通變數之前。

三、效能最佳化點

(1)如何管理狀態物件的建立與銷毀?
第一種僅當state物件被需要時才建立並隨後銷毀(state物件比較龐大,優先選擇),
另一種是一開始就創建好所有的狀態對象,並且始終不銷毀它們(狀態改變頻繁)。
(2)利用享元模式共享一個state物件。

四、JavaScript版本的狀態機

(1)透過Function.prototype.call方法直接把請求委託給某個字面量物件來執行

// 状态机
var FSM = {
  off: {
    buttonWasPressed: function() {
      console.log("关灯");
      this.button.innerHTML = "下一次按我是开灯";   // 这是Light上的属性!!!
      this.currState = FSM.on;            // 这是Light上的属性!!!
    }
  },
  on: {
    buttonWasPressed: function() {
      console.log("开灯");
      this.button.innerHTML = "下一次按我是关灯";
      this.currState = FSM.off;
    }
  },
};

var Light = function() {
  this.currState = FSM.off;  // 设置当前状态
  this.button = null;
};

Light.prototype.init = function() {
  var button = document.createElement("button");
  self = this;

  button.innerHTML = "已关灯";
  this.button = document.body.appendChild(button);
  this.button.onclick = function() {
    // 请求委托给FSM状态机
    self.currState.buttonWasPressed.call(self);
  }

}

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

登入後複製

(2)利用delegate函數

var delegate = function(client, delegation) {
  return {
    buttonWasPressed: function() {
      return delegation.buttonWasPressed.apply(client, arguments);
    }
  };
};

// 状态机
var FSM = {
  off: {
    buttonWasPressed: function() {
      console.log("关灯");
      this.button.innerHTML = "下一次按我是开灯";
      this.currState = this.onState;
    }
  },
  on: {
    buttonWasPressed: function() {
      console.log("开灯");
      this.button.innerHTML = "下一次按我是关灯";
      this.currState = this.offState;
    }
  },
};

var Light = function() {
  this.offState = delegate(this, FSM.off);
  this.onState = delegate(this, FSM.on);
  this.currState = this.offState; // 设置当前状态
  this.button = null;
};

Light.prototype.init = function() {
  var button = document.createElement("button");
  self = this;

  button.innerHTML = "已关灯";
  this.button = document.body.appendChild(button);
  this.button.onclick = function() {
    // 请求委托给FSM状态机
    self.currState.buttonWasPressed();
  }
}

var light = new Light();
light.init();
登入後複製

希望本文所述對大家學習javascript程式設計有所幫助。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java框架中設計模式與架構模式的區別 Java框架中設計模式與架構模式的區別 Jun 02, 2024 pm 12:59 PM

Java框架中設計模式與架構模式的區別

Java設計模式之適配器模式的妙用 Java設計模式之適配器模式的妙用 May 09, 2024 pm 12:54 PM

Java設計模式之適配器模式的妙用

Java設計模式之裝飾器模式剖析 Java設計模式之裝飾器模式剖析 May 09, 2024 pm 03:12 PM

Java設計模式之裝飾器模式剖析

PHP 設計模式實戰案例解析 PHP 設計模式實戰案例解析 May 08, 2024 am 08:09 AM

PHP 設計模式實戰案例解析

java框架中使用設計模式的優缺點有哪些? java框架中使用設計模式的優缺點有哪些? Jun 01, 2024 pm 02:13 PM

java框架中使用設計模式的優缺點有哪些?

Guice框架中設計模式的應用 Guice框架中設計模式的應用 Jun 02, 2024 pm 10:49 PM

Guice框架中設計模式的應用

設計模式如何應對程式碼維護難題 設計模式如何應對程式碼維護難題 May 09, 2024 pm 12:45 PM

設計模式如何應對程式碼維護難題

PHP設計模式:測試驅動開發實踐 PHP設計模式:測試驅動開發實踐 Jun 03, 2024 pm 02:14 PM

PHP設計模式:測試驅動開發實踐

See all articles