js 設計模式——狀態模式

来源:https://www.cnblogs.com/loveyt/archive/2019/08/24/11403784.html
-Advertisement-
Play Games

狀態模式 允許一個對象在其內部狀態改變時改變它的行為,對象看起來似乎修改了它的類。 簡單的解釋一下: 第一部分的意思是將狀態封裝成獨立的類,並將請求委托給當前的狀態對象,當對象的內部狀態改變時,會帶來不同的行為變化。 第二部分是從客戶的角度來看,我們使用的對象,在不同的狀態下具有截然不同的行為,這個 ...


狀態模式

允許一個對象在其內部狀態改變時改變它的行為,對象看起來似乎修改了它的類。

簡單的解釋一下:

  • 第一部分的意思是將狀態封裝成獨立的類,並將請求委托給當前的狀態對象,當對象的內部狀態改變時,會帶來不同的行為變化。
  • 第二部分是從客戶的角度來看,我們使用的對象,在不同的狀態下具有截然不同的行為,這個對象看起來是從不同的類中實例化而來的,實際上這是使用了委托的效果。

現在舉一個網上比較多的例子,沒錯就是電燈的例子(不要煩,請耐心往下看)

// 首先定義了一個Light類
class Light {
  // 定義一個狀態變數
  constructor(){
    this.state = 'off'
  }
  // 定義一個改變狀態的方法
  change(){
    if(this.state === 'off'){
      console.log('開燈')
      this.state = 'on'
    } else {
      console.log('關燈')
      this.state = 'off'
    }
  }
}
// 創建實例
let light = new Light()
// 調用方法
light.change()

噹噹噹噹,到此我們已經編寫了一個狀態機,邏輯簡單又縝密,看起來還有那麼點無懈可擊。BUT,你懂的事實並非如此,人生也沒那麼多的如意。隨著人類的進步,需求也不(de) 斷(cuo) 進(jin) 步(chi)(●'◡'●),於是新的電燈出現了,這電燈可厲害了,第一次點擊弱光,再次點擊強光,再點七彩光,再點emmm關了。

按我們上面的邏輯來寫,那可就刺激了:

  • 首先違反了開閉原則,每次改動都要更改change()方法,使得方法變得不穩定
  • 狀態切換的不明顯,無法一目瞭然的明白一共有多少種狀態
  • 狀態之間的切換關係,不過是往change()方法里添加if、else語句,是change()方法更加難閱讀和維護

那怎麼辦呢?有首歌怎麼唱來著“新的電燈已經出現,怎麼能夠停滯不前”,哈哈,所以狀態模式來了~~~

因為電燈的例子太無聊了,所以我換了一個例子但是呢意思是一樣滴:

  // 單曲迴圈類
  class SingleCycle{
    constructor(self){
      this._self = self
    }
    modeSwitch(){
      console.log('現在是單曲迴圈')
      this._self.setState( this._self.listCirculation )
    }
  }
  // 列表迴圈類
  class ListCirculation{
    constructor(self){
      this._self = self
    }
    modeSwitch(){
      console.log('現在是列表迴圈')
      this._self.setState( this._self.sequentialPlay )
    }
  }
  // 順序播放類
  class SequentialPlay{
    constructor(self){
      this._self = self
    }
    modeSwitch(){
      console.log('現在是順序播放')
      this._self.setState( this._self.shufflePlay )
    }
  }
  // 隨機播放類
  class ShufflePlay{
    constructor(self){
      this._self = self
    }
    modeSwitch(){
      console.log('現在是隨機播放')
      this._self.setState( this._self.singleCycle )
    }
  }
  // 音樂類
  class Music{
    constructor(){
      // 為每個狀態都創建一個狀態對象
      this.singleCycle = new SingleCycle(this)
      this.listCirculation = new ListCirculation(this)
      this.sequentialPlay = new SequentialPlay(this)
      this.shufflePlay = new ShufflePlay(this)
      // 定義初始狀態為順序播放
      this.currState = this.sequentialPlay
    }
    // 切換播放模式
    changeMode(){
      this.currState.modeSwitch()
    }
    // 下一次點擊時的播放狀態
    setState(newState){
      this.currState = newState;
    }
  }
  // 實例化音樂類
  let music = new Music()
  // 調用切換播放模式方法
  music.changeMode()

好了,到此我們改編完成,如果你沒有懵掉,good,如果你懵掉了,往下看:

  1. 首先我們定義了4個狀態類 SingleCycle(單曲迴圈)ListCirculation(列表迴圈)SequentialPlay(順序播放)ShufflePlay(隨機播放)
  2. 每個狀態類都定義了一個變數 _self 來接收 Music(音樂類) 傳過來的 this,還有一個方法 modeSwitch(狀態更改),用來改變下一次要播放的狀態
  3. 然後定義了一個 Music(音樂類) ,首先在裡面為每一個狀態都創建了一個狀態對象,還定義了一個變數 currState 來記錄下一次點擊時的狀態。
  4. 最後就是Music(音樂類)裡面定義的兩種方法 changeMode(切換播放模式)setState(下一次點擊時的播放狀態) 。當我們點擊切換模式的時候,在 changeMode(切換播放模式) 中去調用之前定義好的狀態類中的 modeSwitch(狀態更改) 方法,完成模式切換的同時調用Music(音樂類)中的 setState(下一次點擊時的播放狀態) 方法來對狀態進行改變,保證下一次點擊時切換不同的模式。

通過上面的方法可以看出:

  1. 我們可以在 Music(音樂類) 中清楚的知道一共有多少個狀態,同時 Music(音樂類) 中不再進行任何實質性的操作,而是通過 this.currState.modeSwitch() 交給了當前持有的狀態對象去執行
  2. 狀態的切換規律被事先在每一個狀態類中定義好了,在 Music(音樂類) 中沒有任何一個和狀態切換相關的條件分支語句

悄悄地說,上面的方法還闊以再完美一點呦


小小的拓展

通過上面的介紹我們瞭解到了每一個狀態類都有一個 modeSwitch() 方法,也就意味著我們每次添加狀態類都要寫一個方法,問題來了,人非聖賢,孰能無過?所以咧難免會丟掉的嘛!

然後做一些小小的優化:

// 定義一個State類
class State{
  constructor(self){
    this._self = self
  }
  modeSwitch(){
   throw new Error( '父類的 modeSwitch 方法必須被重寫' )
  }
}

// 狀態類(舉一個為例)

// 單曲迴圈類(繼承State類)
class SingleCycle extends State{
  modeSwitch(){
    console.log('現在是單曲迴圈')
    this._self.setState( this._self.listCirculation )
  }
}

好了完成,當某一天我們忘了寫方法,也能夠快速的定位到錯誤


目前對於狀態模式的理解就這麼多,以後有了新的理解會繼續更新的,溜了溜了(~ ̄▽ ̄)~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原碼,項目中遇到的錯誤,解決方法,文章最後有鏈接可以獲取 項目簡介 功能描述 登陸,註冊,用戶一覽表,修改,刪除,添加,模糊查詢和精確查詢 採用的技術及環境 JSP:前端的信息展示 Servlet:業務邏輯功能實現,及調用資料庫的實現數據處理和傳輸 MySQL:用來實現數據存儲 利用Eclipse來 ...
  • 最近博客背景圖片的外鏈掛了,沒辦法,只好另找辦法。 在博客園後臺,有一個“文件”菜單,可以上傳自己的文件,我就打算把圖片傳到裡面。但卻發現了一個很反人性的設置:不允許上傳jpg,png文件,允許上傳的只有bmp,gif這樣的圖片文件。bmp文件太大,載入都要好幾秒,gif文件質量太差,只有256色, ...
  • 編程思想: 面向過程:凡事親力親為,所有事情的過程都要清楚,註重的是過程。 面向對象:提出需求,找到對象,對象解決這個問題,我們要結果,註重的是結果。 面向對象的特性:封裝,繼承,多態; JS: 是一門解釋性語言,是一門腳本語言,是一門弱類型語言,是一門基於對象的語言,是一門動態類型的語言。 對象: ...
  • 一、React的世界觀1、通過改變state來改變視圖視圖不用考慮如何改變自己,把state畫出來即可。2、變數不可變通過創建一個新的state來更改state,使得變更可追蹤,不容易因為其他部分修改state導致不可預測的錯誤3、結構與樣式分離參考了CSS的做法,RN的style機制使得代碼更清晰 ...
  • js中的數組和字元串有點類似,不是說本質上,而是在遍歷,獲取時的類似。從標識來說,可以一眼看出那個是數組,那個是字元串;但在使用遍歷時,會不經意的將兩者混淆,導致方法用錯。同時兩者的方法又有好幾個相同的,但需註意語義,以及有些方法是不會對原數組產生影響的。以下是我整理的一些關於數組和字元串的一些方法 ...
  • 介紹 在css2當中,存在標準模式下的盒子模型和IE下的怪異盒子模型。這兩種方案表示的是一種盒子模型的渲染模式。而在css3當中,新增加了彈性盒子模型,彈性盒子模型是一種新增加的強大的、靈活的佈局方案。彈性盒子模型是css3中新提出的一種佈局方案。是一種為了應對針對不同屏幕寬度不同設備的一整套新的布 ...
  • 一、什麼是 iframe iframe 用於在頁面內顯示頁面,使用 <iframe> 會創建包含另外一個文檔的內聯框架(即行內框架) 二、iframe 的常用屬性 1、width 定義 iframe 的寬度 2、height 定義 iframe 的高度 3、name 規定 iframe 的名稱 4、 ...
  • HTML5/CSS簡介 首先來說一說什麼是HTML5,HTML5可以認為是字面上的意義,也就是HTML的第五代產品,當然從另一個角度來說它是一種新的富客戶端解決方案。 HTML5 將成為 HTML、XHTML 以及 HTML DOM 的新標準。 HTML 的上一個版本誕生於 1999 年。自從那以後 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...