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()
}
}
--實作結果--
更多的物件導向設計
物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!
創建模式 Creation Patterns
● 創建模式 PK
● 創建模式 - Creation Patterns
:
創建模式用於「物件的創建」,它關注於如何更靈活、更有效地創建物件。這些模式可以隱藏創建物件的細節,並提供創建物件的機制,例如單例模式、工廠模式… 等等,詳細解說請點擊以下連結
● Singleton 單例模式 | 解說實現 | Android Framework Context Service
● Abstract Factory 設計模式 | 實現解說 | Android MediaPlayer
● Factory 工廠方法模式 | 解說實現 | Java 集合設計
● Builder 建構者模式 | 實現與解說 | Android Framwrok Dialog 視窗
● Clone 原型模式 | 解說實現 | Android Framework Intent
行為模式 Behavioral Patterns
● 行為模式 PK
● 行為模式 - Behavioral Patterns
:
行為模式關注物件之間的「通信」和「職責分配」。它們描述了一系列物件如何協作,以完成特定任務。這些模式專注於改進物件之間的通信,從而提高系統的靈活性。例如,策略模式、觀察者模式… 等等,詳細解說請點擊以下連結
● Stragety 策略模式 | 解說實現 | Android Framework 動畫
● Interpreter 解譯器模式 | 解說實現 | Android Framework PackageManagerService
● Chain 責任鏈模式 | 解說實現 | Android Framework View 事件傳遞
● Specification 規格模式 | 解說實現 | Query 語句實做
● Command 命令、Servant 雇工模式 | 實現與解說 | 物件導向設計
● Memo 備忘錄模式 | 實現與解說 | Android Framwrok Activity 保存
● Visitor 設計模式 | 實現與解說 | 物件導向設計
● Template 設計模式 | 實現與解說 | 物件導向設計
● Mediator 模式設計 | 實現與解說 | 物件導向設計
● Composite 組合模式 | 實現與解說 | 物件導向設計
● Observer 觀察者模式 | JDK Observer | Android Framework Listview
結構模式 Structural Patterns
● 結構模式 PK
● 結構模式 - Structural Patterns
:
結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結
● Decorate 裝飾模式 | 解說實現 | 物件導向設計
● Iterator 迭代設計 | 解說實現 | 物件導向設計