JS設計模式之狀態(tài)模式的用法使用方法
狀態(tài)模式(State Pattern)
一種行為型設計模式,核心是對象在其內部狀態(tài)改變時改變其行為。
狀態(tài)模式將對象的行為封裝到不同的狀態(tài)類中,使得對象在不同狀態(tài)下可以選擇不同的行為。
組成
環(huán)境類:環(huán)境類是擁有狀態(tài)的對象,它在運行時將自身的操作委托給當前的狀態(tài)對象來處理。①環(huán)境類維護一個對抽象狀態(tài)類的引用,②并通過該引用來調用具體狀態(tài)類的方法。
抽象狀態(tài)類:抽象狀態(tài)類定義了一個接口③,用于封裝與環(huán)境類的特定狀態(tài)相關的行為。
具體狀態(tài)類:具體狀態(tài)類實現了抽象狀態(tài)類定義的接口,它具體描述了在某個狀態(tài)下對象的行為④。
工作流程
環(huán)境類通過持有一個抽象狀態(tài)類的引用來表示當前的狀態(tài)。
客戶端通過調用環(huán)境類的方法來觸發(fā)某個操作。
環(huán)境類在運行時將操作委托給當前狀態(tài)對象進行處理。
當對象的狀態(tài)發(fā)生改變時,環(huán)境類會更新當前狀態(tài)對象的引用,從而改變對象的行為。
趣例
下面的這個例子展示了一位西安老鐵觀看國足比賽的時候的心理狀態(tài)變化過程:
abstract class State {
? constructor(public context: Context | null = null) {}
? // 這里體現出③:用于封裝與環(huán)境類的特定狀態(tài)相關的行為
? handle() {
? ? if (!this.context) {
? ? ? console.log("找不到老鐵了!");
? ? } else {
? ? ? this.exec();
? ? }
? }
? next<T extends State>(NextState: new (context: Context) => T) {
? ? if (!this.context) {
? ? ? console.log("找不到老鐵了!");
? ? } else {
? ? ? this.context.to(new NextState(this.context));
? ? }
? }
? abstract exec(): any;
}
// 具體狀態(tài)類
class StateA extends State {
? // 這里體現出④:用于封裝與環(huán)境類的特定狀態(tài)相關的行為
? exec() {
? ? console.log("買票");
? ? this.next(StateB);
? }
}
class StateB extends State {
? exec() {
? ? console.log("坐車");
? ? this.next(StateC);
? }
}
class StateC extends State {
? exec() {
? ? console.log("看球");
? ? this.next(StateO);
? }
}
class StateO extends State {
? exec() {
? ? throw new Error('已經結束了');
? }
}
// 環(huán)境類
class Context {
? // 這里體現出①:環(huán)境類維護一個對抽象狀態(tài)類的引用,即cts
? constructor(public cts: State | null = null) {}
? to(state: State) {
? ? console.log(`Transitioning to ${state.constructor.name}`);
? ? this.cts = state;
? }
? do() {
? ? // 這里體現出②:通過該引用來調用具體狀態(tài)類的方法
? ? this.cts?.handle();
? }
}
// 使用示例
const context = new Context();
const stateA = new StateA(context);
context.to(stateA);
while(1){
? try {
? ? context.do();
? } catch {
? ? console.log('肯定輸了!');
? ? break;
? }
}對照例子理解
- 狀態(tài)模式:一種行為型設計模式,核心是①【對象】在其②【內部狀態(tài)】③【改變】時④【改變其行為】。
①對象:指的是環(huán)境類對象,也就是上述代碼中的context對象。
②內部狀態(tài),指的是context引用的狀態(tài)類實例,也就是stateA以及NextState的匿名實例。
③改變:指的是context.to的調用。
④行為:指的是context.do函數的執(zhí)行結果。
改變其行為:指的是context.cts引用不同的狀態(tài)類實例的時候context.do的執(zhí)行結果不同。
狀態(tài)模式將對象的行為封裝到不同的狀態(tài)類中,使得對象在不同狀態(tài)下可以選擇不同的行為。
這句話理解成:
本來應該在context.do中通過if else實現的功能,被封裝到了不同的狀態(tài)類中(StateA StateB);
當context的狀態(tài)改變的時候(即:context.cts引用不同的狀態(tài)類實例的時候)context.do也能實現封裝前相同的功能(即表現出不同的行為)。
見下面代碼:
不使用狀態(tài)設計模式實現上述代碼功能:
class Context {
? state = 'A';
? to(state: string) {
? ? console.log(`Transitioning to state ${state}`);
? ? this.state = state;
? }
? do() {
? ? if(this.state === 'A'){
? ? ? console.log("買票");
? ? ? this.to('B');
? ? } else if (this.state === 'B') {
? ? ? console.log("坐車");
? ? ? this.to('C');
? ? } else if (this.state === 'C') {
? ? ? console.log("看球");
? ? ? this.to('D');
? ? } else if (this.state === 'D') {
? ? ? throw new Error('已經結束了');
? ? }
? }
}
const context = new Context();
while(1){
? try {
? ? context.do();
? } catch {
? ? console.log('肯定輸了!');
? ? break;
? }
}【對比】雖然這樣看起來代碼量好像少了一些,但是如果老鐵想要在下車后去趟衛(wèi)生間,使用了狀態(tài)設計模式的代碼只需要修改StateB的實現就可以了,而后者則必須修改Context中的do方法!
優(yōu)點
封裝之后的狀態(tài)可以獨立變化,符合開閉原則。
狀態(tài)模式提供了一種清晰的方式來組織對象的行為,并避免了使用大量的條件語句。
缺點
狀態(tài)較多時,導致狀態(tài)類的數量增加,增加系統(tǒng)的復雜性。
對象在不同狀態(tài)下的轉換邏輯可能會分散在多個狀態(tài)類中,使得代碼難以理解和維護。
如果某個狀態(tài)只被一個對象使用,可以考慮使用策略模式替代狀態(tài)模式。
應用
狀態(tài)模式常見于需要根據對象的內部狀態(tài)來改變其行為的場景,例如【訂單狀態(tài)的處理】、【游戲角色的狀態(tài)轉換】等。
它提供了一種可擴展的方式來處理狀態(tài)相關的邏輯,并促進了代碼的靈活性和可維護性。
generator函數可以看成原生js實現了狀態(tài)設計模式。
感性記憶
同一個對象,當其內部維護的狀態(tài)不同的時候,調用其上的同一個方法,可能會得到完全不同的結果。
總結
就是適用于同一個對象具有不同的狀態(tài),并且在各個狀態(tài)下表現不一致的情況;這些狀態(tài)之間如果是可以相互轉換的,使用此設計模式就更加合適了。
到此這篇關于JS設計模式之狀態(tài)模式的用法使用方法的文章就介紹到這了,更多相關JS狀態(tài)模式使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
淺析JavaScriptSerializer類的序列化與反序列化
本篇文章主要介紹了JavaScriptSerializer類 對象序列化與反序列化的方法、屬性以及實例代碼,有需要的朋友可以參考一下2016-11-11
詳解微信圖片防盜鏈“此圖片來自微信公眾平臺 未經允許不得引用”的解決方案
這篇文章主要介紹了詳解微信圖片防盜鏈“此圖片來自微信公眾平臺 未經允許不得引用”的解決方案,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04
bootstrap modal+gridview實現彈出框效果
這篇文章主要介紹了bootstrap modal+gridview實現彈出框效果,gridview點擊更新彈出填寫信息表單,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08

