欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go設計模式之狀態(tài)模式圖文詳解

 更新時間:2023年08月11日 08:33:22   作者:demo007x  
狀態(tài)模式是一種行為設計模式, 讓你能在一個對象的內部狀態(tài)變化時改變其行為, 使其看上去就像改變了自身所屬的類一樣,本文將通過一些圖片來給大家詳細的介紹一下Go的狀態(tài)模式,需要的朋友可以參考下

狀態(tài)模式 (State)

狀態(tài)模式是一種行為設計模式, 讓你能在一個對象的內部狀態(tài)變化時改變其行為, 使其看上去就像改變了自身所屬的類一樣。

問題

狀態(tài)模式與有限狀態(tài)機 的概念緊密相關。

有限狀態(tài)機

其主要思想是程序在任意時刻僅可處于幾種有限的狀態(tài)中。 在任何一個特定狀態(tài)中, 程序的行為都不相同, 且可瞬間從一個狀態(tài)切換到另一個狀態(tài)。 不過, 根據(jù)當前狀態(tài), 程序可能會切換到另外一種狀態(tài), 也可能會保持當前狀態(tài)不變。 這些數(shù)量有限且預先定義的狀態(tài)切換規(guī)則被稱為轉移。

你還可將該方法應用在對象上。 假如你有一個 文檔 Document類。 文檔可能會處于 草稿 Draft 、 審閱中 Moderation和 已發(fā)布 Published三種狀態(tài)中的一種。 文檔的 publish 發(fā)布方法在不同狀態(tài)下的行為略有不同:

  • 處于 草稿 狀態(tài)時, 它會將文檔轉移到審閱中狀態(tài)。
  • 處于 審閱中 狀態(tài)時, 如果當前用戶是管理員, 它會公開發(fā)布文檔。
  • 處于 已發(fā)布 狀態(tài)時, 它不會進行任何操作。

文檔對象的全部狀態(tài)

狀態(tài)機通常由眾多條件運算符 ( if switch ) 實現(xiàn), 可根據(jù)對象的當前狀態(tài)選擇相應的行為。 “狀態(tài)” 通常只是對象中的一組成員變量值。 即使你之前從未聽說過有限狀態(tài)機, 你也很可能已經(jīng)實現(xiàn)過狀態(tài)模式。 下面的代碼應該能幫助你回憶起來。

class Document is
    field state: string
    // ……
    method publish() is
        switch (state)
            "draft":
                state = "moderation"
                break
            "moderation":
                if (currentUser.role == "admin")
                    state = "published"
                break
            "published":
                // 什么也不做。
                break
    // ……

當我們逐步在 文檔 類中添加更多狀態(tài)和依賴于狀態(tài)的行為后, 基于條件語句的狀態(tài)機就會暴露其最大的弱點。 為了能根據(jù)當前狀態(tài)選擇完成相應行為的方法, 絕大部分方法中會包含復雜的條件語句。 修改其轉換邏輯可能會涉及到修改所有方法中的狀態(tài)條件語句, 導致代碼的維護工作非常艱難。

這個問題會隨著項目進行變得越發(fā)嚴重。 我們很難在設計階段預測到所有可能的狀態(tài)和轉換。 隨著時間推移, 最初僅包含有限條件語句的簡潔狀態(tài)機可能會變成臃腫的一團亂麻。

解決方案

狀態(tài)模式建議為對象的所有可能狀態(tài)新建一個類, 然后將所有狀態(tài)的對應行為抽取到這些類中。

原始對象被稱為上下文 (context), 它并不會自行實現(xiàn)所有行為, 而是會保存一個指向表示當前狀態(tài)的狀態(tài)對象的引用, 且將所有與狀態(tài)相關的工作委派給該對象。

文檔將工作委派給一個狀態(tài)對象

如需將上下文轉換為另外一種狀態(tài), 則需將當前活動的狀態(tài)對象替換為另外一個代表新狀態(tài)的對象。 采用這種方式是有前提的: 所有狀態(tài)類都必須遵循同樣的接口, 而且上下文必須僅通過接口與這些對象進行交互。

這個結構可能看上去與策略模式相似, 但有一個關鍵性的不同——在狀態(tài)模式中, 特定狀態(tài)知道其他所有狀態(tài)的存在, 且能觸發(fā)從一個狀態(tài)到另一個狀態(tài)的轉換; 策略則幾乎完全不知道其他策略的存在。

真實世界類比

智能手機的按鍵和開關會根據(jù)設備當前狀態(tài)完成不同行為:

  • 當手機處于解鎖狀態(tài)時, 按下按鍵將執(zhí)行各種功能。
  • 當手機處于鎖定狀態(tài)時, 按下任何按鍵都將解鎖屏幕。
  • 當手機電量不足時, 按下任何按鍵都將顯示充電頁面。

狀態(tài)模式結構

狀態(tài)設計模式的結構

  1. 上下文 (Context) 保存了對于一個具體狀態(tài)對象的引用, 并會將所有與該狀態(tài)相關的工作委派給它。 上下文通過狀態(tài)接口與狀態(tài)對象交互, 且會提供一個設置器用于傳遞新的狀態(tài)對象。

  2. 狀態(tài) (State) 接口會聲明特定于狀態(tài)的方法。 這些方法應能被其他所有具體狀態(tài)所理解, 因為你不希望某些狀態(tài)所擁有的方法永遠不會被調用。

  3. 具體狀態(tài) (Concrete States) 會自行實現(xiàn)特定于狀態(tài)的方法。 為了避免多個狀態(tài)中包含相似代碼, 你可以提供一個封裝有部分通用行為的中間抽象類。

    狀態(tài)對象可存儲對于上下文對象的反向引用。 狀態(tài)可以通過該引用從上下文處獲取所需信息, 并且能觸發(fā)狀態(tài)轉移。

  4. 上下文和具體狀態(tài)都可以設置上下文的下個狀態(tài), 并可通過替換連接到上下文的狀態(tài)對象來完成實際的狀態(tài)轉換。

偽代碼

在本例中, 狀態(tài)模式將根據(jù)當前回放狀態(tài), 讓媒體播放器中的相同控件完成不同的行為。

狀態(tài)模式示例的結構

使用狀態(tài)對象更改對象行為的示例。

播放器的主要對象總是會連接到一個負責播放器絕大部分工作的狀態(tài)對象中。 部分操作會更換播放器當前的狀態(tài)對象, 以此改變播放器對于用戶互動所作出的反應。

// 音頻播放器(Audio-Player)類即為上下文。它還會維護指向狀態(tài)類實例的引用,
// 該狀態(tài)類則用于表示音頻播放器當前的狀態(tài)。
class AudioPlayer is
    field state: State
    field UI, volume, playlist, currentSong
    constructor AudioPlayer() is
        this.state = new ReadyState(this)
        // 上下文會將處理用戶輸入的工作委派給狀態(tài)對象。由于每個狀態(tài)都以不
        // 同的方式處理輸入,其結果自然將依賴于當前所處的狀態(tài)。
        UI = new UserInterface()
        UI.lockButton.onClick(this.clickLock)
        UI.playButton.onClick(this.clickPlay)
        UI.nextButton.onClick(this.clickNext)
        UI.prevButton.onClick(this.clickPrevious)
    // 其他對象必須能切換音頻播放器當前所處的狀態(tài)。
    method changeState(state: State) is
        this.state = state
    // UI 方法會將執(zhí)行工作委派給當前狀態(tài)。
    method clickLock() is
        state.clickLock()
    method clickPlay() is
        state.clickPlay()
    method clickNext() is
        state.clickNext()
    method clickPrevious() is
        state.clickPrevious()
    // 狀態(tài)可調用上下文的一些服務方法。
    method startPlayback() is
        // ……
    method stopPlayback() is
        // ……
    method nextSong() is
        // ……
    method previousSong() is
        // ……
    method fastForward(time) is
        // ……
    method rewind(time) is
        // ……
// 所有具體狀態(tài)類都必須實現(xiàn)狀態(tài)基類聲明的方法,并提供反向引用指向與狀態(tài)相
// 關的上下文對象。狀態(tài)可使用反向引用將上下文轉換為另一個狀態(tài)。
abstract class State is
    protected field player: AudioPlayer
    // 上下文將自身傳遞給狀態(tài)構造函數(shù)。這可幫助狀態(tài)在需要時獲取一些有用的
    // 上下文數(shù)據(jù)。
    constructor State(player) is
        this.player = player
    abstract method clickLock()
    abstract method clickPlay()
    abstract method clickNext()
    abstract method clickPrevious()
// 具體狀態(tài)會實現(xiàn)與上下文狀態(tài)相關的多種行為。
class LockedState extends State is
    // 當你解鎖一個鎖定的播放器時,它可能處于兩種狀態(tài)之一。
    method clickLock() is
        if (player.playing)
            player.changeState(new PlayingState(player))
        else
            player.changeState(new ReadyState(player))
    method clickPlay() is
        // 已鎖定,什么也不做。
    method clickNext() is
        // 已鎖定,什么也不做。
    method clickPrevious() is
        // 已鎖定,什么也不做。
// 它們還可在上下文中觸發(fā)狀態(tài)轉換。
class ReadyState extends State is
    method clickLock() is
        player.changeState(new LockedState(player))
    method clickPlay() is
        player.startPlayback()
        player.changeState(new PlayingState(player))
    method clickNext() is
        player.nextSong()
    method clickPrevious() is
        player.previousSong()
class PlayingState extends State is
    method clickLock() is
        player.changeState(new LockedState(player))
    method clickPlay() is
        player.stopPlayback()
        player.changeState(new ReadyState(player))
    method clickNext() is
        if (event.doubleclick)
            player.nextSong()
        else
            player.fastForward(5)
    method clickPrevious() is
        if (event.doubleclick)
            player.previous()
        else
            player.rewind(5)

狀態(tài)模式適合應用場景

  • 如果對象需要根據(jù)自身當前狀態(tài)進行不同行為, 同時狀態(tài)的數(shù)量非常多且與狀態(tài)相關的代碼會頻繁變更的話, 可使用狀態(tài)模式。

模式建議你將所有特定于狀態(tài)的代碼抽取到一組獨立的類中。 這樣一來, 你可以在獨立于其他狀態(tài)的情況下添加新狀態(tài)或修改已有狀態(tài), 從而減少維護成本。

  • 如果某個類需要根據(jù)成員變量的當前值改變自身行為, 從而需要使用大量的條件語句時, 可使用該模式。

狀態(tài)模式會將這些條件語句的分支抽取到相應狀態(tài)類的方法中。 同時, 你還可以清除主要類中與特定狀態(tài)相關的臨時成員變量和幫手方法代碼。

  • 當相似狀態(tài)和基于條件的狀態(tài)機轉換中存在許多重復代碼時, 可使用狀態(tài)模式。

狀態(tài)模式讓你能夠生成狀態(tài)類層次結構, 通過將公用代碼抽取到抽象基類中來減少重復。

實現(xiàn)方式

  1. 確定哪些類是上下文。 它可能是包含依賴于狀態(tài)的代碼的已有類; 如果特定于狀態(tài)的代碼分散在多個類中, 那么它可能是一個新的類。

  2. 聲明狀態(tài)接口。 雖然你可能會需要完全復制上下文中聲明的所有方法, 但最好是僅把關注點放在那些可能包含特定于狀態(tài)的行為的方法上。

  3. 為每個實際狀態(tài)創(chuàng)建一個繼承于狀態(tài)接口的類。 然后檢查上下文中的方法并將與特定狀態(tài)相關的所有代碼抽取到新建的類中。

    在將代碼移動到狀態(tài)類的過程中, 你可能會發(fā)現(xiàn)它依賴于上下文中的一些私有成員。 你可以采用以下幾種變通方式:

    • 將這些成員變量或方法設為公有。
    • 將需要抽取的上下文行為更改為上下文中的公有方法, 然后在狀態(tài)類中調用。 這種方式簡陋卻便捷, 你可以稍后再對其進行修補。
    • 將狀態(tài)類嵌套在上下文類中。 這種方式需要你所使用的編程語言支持嵌套類。
  4. 在上下文類中添加一個狀態(tài)接口類型的引用成員變量, 以及一個用于修改該成員變量值的公有設置器。

  5. 再次檢查上下文中的方法, 將空的條件語句替換為相應的狀態(tài)對象方法。

  6. 為切換上下文狀態(tài), 你需要創(chuàng)建某個狀態(tài)類實例并將其傳遞給上下文。 你可以在上下文、 各種狀態(tài)或客戶端中完成這項工作。 無論在何處完成這項工作, 該類都將依賴于其所實例化的具體類。

狀態(tài)模式優(yōu)缺點

  • 單一職責原則。 將與特定狀態(tài)相關的代碼放在單獨的類中。

  • 開閉原則。 無需修改已有狀態(tài)類和上下文就能引入新狀態(tài)。

  • 通過消除臃腫的狀態(tài)機條件語句簡化上下文代碼。

  • 如果狀態(tài)機只有很少的幾個狀態(tài), 或者很少發(fā)生改變, 那么應用該模式可能會顯得小題大作。

代碼示例

Go設計模式之狀態(tài)模式講解和代碼示例_Golang_腳本之家 (jb51.net)

以上就是Go設計模式之狀態(tài)模式圖文詳解的詳細內容,更多關于Go狀態(tài)模式的資料請關注腳本之家其它相關文章!

相關文章

  • Golang的性能優(yōu)化和調試技巧

    Golang的性能優(yōu)化和調試技巧

    在開發(fā)和部署Go語言應用程序時,性能優(yōu)化和調試是至關重要的,篇博客將介紹一些常用的Golang性能優(yōu)化和調試技巧,幫助您提升應用程序的性能并解決潛在的問題
    2023-05-05
  • 初探GO中unsafe包的使用

    初探GO中unsafe包的使用

    unsafe是Go語言標準庫中的一個包,提供了一些不安全的編程操作,本文將深入探討Go語言中的unsafe包,介紹它的使用方法和注意事項,感興趣的可以了解下
    2023-08-08
  • Go語言學習之結構體和方法使用詳解

    Go語言學習之結構體和方法使用詳解

    這篇文章主要為大家詳細介紹了Go語言中結構體和方法的使用,文中的示例代碼講解詳細,對我們學習Go語言有一定的幫助,需要的可以參考一下
    2022-04-04
  • 一文總結Go語言切片核心知識點和坑

    一文總結Go語言切片核心知識點和坑

    都說Go的切片用起來絲滑得很,Java中的List怎么用,切片就怎么用,作為曾經(jīng)的Java選手,因為切片的使用不得當,喜提缺陷若干,本文就給大家總結一下Go語言切片核心知識點和坑,需要的朋友可以參考下
    2023-06-06
  • 一篇文章說清楚?go?get?使用私有庫的方法

    一篇文章說清楚?go?get?使用私有庫的方法

    這篇文章主要介紹了go?get?如何使用私有庫,本文會明確指出Git?、golang的配置項,附送TortoiseGit?+?Git混合配置,需要的朋友可以參考下
    2022-09-09
  • Go語言無緩沖的通道的使用

    Go語言無緩沖的通道的使用

    Go語言中無緩沖的通道是指在接收前沒有能力保存任何值的通道,本文主要介紹了Go語言無緩沖的通道的使用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Golang的關鍵字defer的使用方法

    Golang的關鍵字defer的使用方法

    這篇文章主要介紹了Golang的關鍵字defer的使用方法,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-06-06
  • Go中defer使用場景及注意事項

    Go中defer使用場景及注意事項

    defer 會在當前函數(shù)返回前執(zhí)行傳入的函數(shù),它會經(jīng)常被用于關閉文件描述符、關閉數(shù)據(jù)庫連接以及解鎖資源。這篇文章主要介紹了Go中defer使用注意事項,需要的朋友可以參考下
    2021-12-12
  • 深入了解Golang中占位符的使用

    深入了解Golang中占位符的使用

    在寫?golang?的時候,也是有對應的格式控制符,也叫做占位符,寫這個占位符,需要有對應的數(shù)據(jù)與之對應,不能瞎搞。本文就來和大家聊聊Golang中占位符的使用,希望對大家有所幫助
    2023-03-03
  • 并發(fā)安全本地化存儲go-cache讀寫鎖實現(xiàn)多協(xié)程并發(fā)訪問

    并發(fā)安全本地化存儲go-cache讀寫鎖實現(xiàn)多協(xié)程并發(fā)訪問

    這篇文章主要介紹了并發(fā)安全本地化存儲go-cache讀寫鎖實現(xiàn)多協(xié)程并發(fā)訪問,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10

最新評論