讓物件的行為隨內部狀態改變,看起來像「換了一個類別」。核心是把每個狀態抽成獨立物件、各自實作行為,並由狀態自己決定下一個狀態,取代散落各處依狀態判斷的
if/else。
🧠 When to Use
TIP
訊號:同一個方法的行為要看「目前處在哪個狀態」而不同,而你正在每個方法裡重複寫 when(state),加一個狀態就得改好幾處。
- 物件有明確的狀態機:多個狀態、各自有不同行為與合法轉移。
- 大量行為依
state欄位分支,且這些分支散落在多個方法裡。 - 狀態之間的轉移規則本身就是核心邏輯,想集中、講清楚。
⚖️ Structure & Variants
經典版 — 每個狀態一個類別,狀態自己決定轉移
interface State { fun next(m: TrafficLight) }
object Red : State {
override fun next(m: TrafficLight) { m.state = Green } // ← 狀態自己轉移
}
object Green : State {
override fun next(m: TrafficLight) { m.state = Yellow }
}
object Yellow : State {
override fun next(m: TrafficLight) { m.state = Red }
}
class TrafficLight {
var state: State = Red
fun tick() = state.next(this)
}
val light = TrafficLight()
light.tick() // Red -> GreenTrafficLight不含任何if;轉移規則內聚在各狀態物件裡。
用 sealed class + when 收斂(Kotlin 風)
- 狀態數量固定、轉移簡單時,用
sealed class列舉狀態、在一處when窮舉轉移,編譯器幫你檢查有沒有漏接,常比一堆類別更好維護。
和 Strategy 的差別(結構同形)
- Strategy:由外部選定演算法,物件存活期內通常不自己換。
- State:狀態物件自己決定下一個狀態,行為隨內部流轉而變。
- 結構幾乎一樣,差在「誰決定切換、切換語意是不是狀態機」。
⚠️ Misuse & Anti-patterns
- 狀態其實只有兩三種、轉移很單純:開一堆類別反而比
when難讀,先用 enum / sealed class。 - 轉移規則散落各處:State 的價值就在把轉移集中;若每個狀態又回頭散寫條件判斷,等於沒解掉。
- 狀態物件偷藏共享可變資料:狀態若有實例欄位且被多個 context 共用,會互相污染;無狀態時用
object單例化。
🔑 Takeaways
- 本質是「把狀態變成物件、由狀態自己決定轉移」,消滅散落的
when(state)。 - 和 Strategy 同構,靠「誰決定切換」區分。
- 狀態少又簡單時,Kotlin 的 sealed class + 窮舉
when往往比經典版更划算。
No notes yet — jot your takeaways or Q&A here.