State 狀態模式 | 實現解說 | 物件導向設計

State 狀態模式 | 實現解說 | 物件導向設計

Overview of Content

如有引用參考請詳註出處,感謝

本文探討 State(狀態)模式在物件導向設計中的應用與實現。首先,我們將介紹 State 模式的基本概念,並探討其在軟體設計中的使用場景。接著,透過定義 State 及使用 UML 建模的方式,我們將詳細探討 State 模式的設計原則以及相應的優缺點

在了解 State 模式的基礎後,我們將轉向實際的實現部分,論述為何在某些情境下選擇使用 State 設計,並提供 State 標準實現的範例

透過本文的解說,讀者將能夠更全面地理解 State 模式在物件導向設計中的運作方式及其在實際應用中的價值。


State 設計使用場景

A. 物件 行為取決於狀態時,也就是 同樣的行為,在不同狀態下會有不一樣的實作

行為受狀態約束時,可以很好的使用這個設計

但建議狀態不要超過 5 個以上

● 當物件內部改變狀態(切換 State)時,像是改變了整個類別

B. 大量 if/else or switch/case 在判斷狀態,再透過狀態來決定行為時

State 定義 & State UML

State 定義

一個物件內部狀態改變時允許對相同行為有不同動作,看起來像是改變了物件

State UML策略模式 幾乎相同,但是 它不可相互取代 每種狀態都有特殊意義

功能
Context環境角色,負責具體狀態的切換(商業邏輯)
IState共同行為的抽象宣告
ConstateA、B它有兩個責任:具體行為的實作(當前狀態)、狀態切換的行為(過渡到令一個狀態)

State & Stragety 設計差異 ?

主要要概念上的差異,State 每個實作都是 無法互相取代,每個狀態之間有關係,並且每個狀態要過渡到個別不同狀態(當前 -> 下一個狀態)

State 設計:優缺點

State 設計優點

● 保證 狀態的擴充性

● 保證 可維護性(不會影響到之前的正常功能)

● 狀態模式 配合 建造者模式,可以起到一個很好的封裝作用

可以依照建造順序產生多種不同狀態

State 設計缺點

● 狀態增加時必定會增加其子類


State 實現

謂何要使用 State 設計?

● 在實現 State 設計之前我們先來看看問題點在哪,為何我們要使用 State 設計

從下面的程式中可以看出,它把所有功能都集合在 McuControl,如果需要修改、新增狀態,就必須修改已經完成的 Function

● 問題點 ?

新增狀態時,須手動修改已完成的類,並不符合開閉原則


class McuControl {
    enum class State {
        ON,
        OFF
    }

    private var curState = State.OFF
    fun setState(state: State) {
        if (state != curState) {
            curState = state
        }
    }

    fun start() {
        when (curState) {
            State.ON -> println("MCU already on.")
            State.OFF -> println("MCU turn on.")
        }
    }

    fun stop() {
        when (curState) {
            State.ON -> println("MCU turn off.")
            State.OFF -> println("MCU already off.")
        }
    }

    fun showLed() {
        when (curState) {
            State.ON -> println("Shiny ~ Shiny ~ Shiny ~.")
            State.OFF -> println("Turn on MCU first.")
        }
    }
}

State 標準實現

A. IState:透過 IControl 類,宣告 狀態的共同方法,也就是 所有狀態的行為


// IState.java

public interface IControl {
    void start();

    void stop();

    void showLed();
}

B. ConstateA、B :具體實現 IControl 類的細節,這裡有兩個重點,^1.^ 實現 MCU 個 On/Off 兩種狀態 針對這兩種狀況作出不同反應、^2.^ 透過環境角色切換狀態

狀態的切換(過渡)是狀態模式很重要的一件事情!



// 開啟模式
class PowerOnMode(private val context: Context) : IControl {

override fun start() {
// 透過狀態角色 切換狀態
context.setContext(Context.State.POWER_ON)
// do nothing
}

override fun stop() {
// 透過狀態角色 切換狀態
context.setContext(Context.State.POWER_OFF)
println("MCU turn off.")
}

override fun showLed() {
println("Shiny ~ Shiny ~ Shiny ~.")
}
}

// ---------------------------------------------------------------
// 關閉模式
class PowerOffMode(private val context: Context) : IControl {

override fun start() {
// 透過狀態角色 切換狀態
context.setContext(Context.State.POWER_ON)
println("MCU turn on.")
}

override fun stop() {
// 透過狀態角色 切換狀態
context.setContext(Context.State.POWER_OFF)
// do nothing
}

override fun showLed() {
// do nothing
}
}

C. Context:環境切換角色,它擁有所有的狀態,並且也透過它來切換不同的狀態模式

● 這裡可以看到 Context 對外提供的方法與 IControl 提供的相同,那它可以實做 IControl 嗎?

建議不要!這邊應該要考慮到 Context 其實可以不需要跟 IControl 有相同方法,它應該對外提供自身的方法,而這裡只是剛好相同而已


class Context {

    private val powerOn = PowerOnMode(this)
    private val powerOff = PowerOffMode(this)

    enum class State {
        POWER_ON,
        POWER_OFF
    }

    private var curContext: IControl? = null

    fun setContext(state: State) {
        curContext = when(state) {
            State.POWER_ON -> powerOn
            State.POWER_OFF -> powerOff
        }
    }

    fun start() {
        curContext?.start()
    }

    fun stop() {
        curContext?.stop()
    }

    fun showLed() {
        curContext?.showLed()
    }

}

● User 使用:透過替換抽象,來達成相同功能 (抽象),不同行為 (細節)


fun main() {

    val contextEnv = Context().apply {
        setContext(Context.State.POWER_OFF)
    }

    contextEnv.apply {
        start()

        showLed()

        stop()

        showLed()
    }

}

--實作結果--


更多的物件導向設計

物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!

設計建模 2 大概念- UML 分類、使用

物件導向設計原則 – 6 大原則(一)

物件導向設計原則 – 6 大原則(二)

創建、行為、結構型設計 8 個比較 | 包裝模式 | 最佳實踐

創建模式 Creation Patterns

創建模式 PK

創建模式 - Creation Patterns

結構模式 Structural Patterns

結構模式 PK

結構模式 - Structural Patterns

結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結

Bridge 橋接模式 | 解說實現 | 物件導向設計

Decorate 裝飾模式 | 解說實現 | 物件導向設計

Proxy 代理模式 | 解說實現 | 分析動態代理

Iterator 迭代設計 | 解說實現 | 物件導向設計

Facade 外觀、門面模式 | 解說實現 | 物件導向設計

Adapter 設計模式 | 解說實現 | 物件導向設計

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

發表迴響