天天看點

設計模式 - 狀态模式 - JavaScript

狀态模式:對象行為是根據狀态改變,而改變的。

專注前端與算法的系列幹貨分享。

引用請聲明:xxoo521.com | 「公衆号:心譚部落格」

什麼是“狀态模式”?

狀态模式:對象行為是根據狀态改變,而改變的。

正是由于内部狀态的變化,導緻對外的行為發生了變化。例如:相同的方法在不同時刻被調用,行為可能會有差異。

優缺點

優點:

  • 封裝了轉化規則,對于大量分支語句,可以考慮使用狀态類進一步封裝。
  • 每個狀态都是确定的,對象行為是可控的。

缺點:狀态模式的實作關鍵是将事物的狀态都封裝成單獨的類,這個類的各種方法就是“此種狀态對應的表現行為”。是以,程式開銷會增大。

代碼實作

ES6 實作

在 JavaScript 中,可以直接用 JSON 對象來代替狀态類。

下面代碼展示的就是 FSM(有限狀态機)裡面有 3 種狀态:

download

pause

deleted

。控制狀态轉化的代碼也在其中。

DownLoad

類就是,常說的

Context

對象,它的行為會随着狀态的改變而改變。

const FSM = (() => {
    let currenState = "download";
    return {
        download: {
            click: () => {
                console.log("暫停下載下傳");
                currenState = "pause";
            },
            del: () => {
                console.log("先暫停, 再删除");
            }
        },
        pause: {
            click: () => {
                console.log("繼續下載下傳");
                currenState = "download";
            },
            del: () => {
                console.log("删除任務");
                currenState = "deleted";
            }
        },
        deleted: {
            click: () => {
                console.log("任務已删除, 請重新開始");
            },
            del: () => {
                console.log("任務已删除");
            }
        },
        getState: () => currenState
    };
})();

class Download {
    constructor(fsm) {
        this.fsm = fsm;
    }

    handleClick() {
        const { fsm } = this;
        fsm[fsm.getState()].click();
    }

    hanldeDel() {
        const { fsm } = this;
        fsm[fsm.getState()].del();
    }
}

// 開始下載下傳
let download = new Download(FSM);

download.handleClick(); // 暫停下載下傳
download.handleClick(); // 繼續下載下傳
download.hanldeDel(); // 下載下傳中,無法執行删除操作
download.handleClick(); // 暫停下載下傳
download.hanldeDel(); // 删除任務           

複制

Python3 實作

python 的代碼采用的是“面向對象”的程式設計,沒有過度使用函數式的閉包寫法(python 寫起來也不難)。

是以,負責狀态轉化的類,專門拿出來單獨封裝。

其他 3 個狀态類的狀态,均由這個狀态類來管理。

# 負責狀态轉化
class StateTransform:
  def __init__(self):
    self.__state = 'download'
    self.__states = ['download', 'pause', 'deleted']

  def change(self, to_state):
    if (not to_state) or (to_state not in self.__states) :
      raise Exception('state is unvalid')
    self.__state = to_state

  def get_state(self):
    return self.__state

# 以下是三個狀态類

class DownloadState:
  def __init__(self, transfomer):
    self.__state = 'download'
    self.__transfomer = transfomer

  def click(self):
    print('暫停下載下傳')
    self.__transfomer.change('pause')

  def delete(self):
    print('先暫停, 再删除')

class PauseState:
  def __init__(self, transfomer):
    self.__state = 'pause'
    self.__transfomer = transfomer

  def click(self):
    print('繼續下載下傳')
    self.__transfomer.change('download')

  def delete(self):
    print('删除任務')
    self.__transfomer.change('deleted')

class DeletedState:
  def __init__(self, transfomer):
    self.__state = 'deleted'
    self.__transfomer = transfomer

  def click(self):
    print('任務已删除, 請重新開始')

  def delete(self):
    print('任務已删除')

# 業務代碼
class Download:
  def __init__(self):
    self.state_transformer = StateTransform()
    self.state_map = {
      'download': DownloadState(self.state_transformer),
      'pause': PauseState(self.state_transformer),
      'deleted': DeletedState(self.state_transformer)
    }

  def handle_click(self):
    state = self.state_transformer.get_state()
    self.state_map[state].click()

  def handle_del(self):
    state = self.state_transformer.get_state()
    self.state_map[state].delete()

if __name__ == '__main__':
  download = Download()
  download.handle_click(); # 暫停下載下傳
  download.handle_click(); # 繼續下載下傳
  download.handle_del(); # 下載下傳中,無法執行删除操作
  download.handle_click(); # 暫停下載下傳
  download.handle_del(); # 删除任務           

複制

參考

  • 23 種設計模式全解析
  • 菜鳥教程狀态模式
  • 《JavaScript 設計模式與開發實踐》