Niclas Nilsson
現實世界中的狀態#
現實世界中,人們對**狀態(state)**的態度相當隨意。你要不是有牛奶,就是沒有——沒有所謂「快要沒牛奶了」的量化狀態。但不幸的是,許多程式設計師對程式碼中的狀態也同樣模糊——而這是一個問題。
網路商店的例子#
考慮一個只接受信用卡、不需開發票的簡單網路商店,其中 Order 類別有以下方法:
public boolean isComplete() {
return isPaid() && hasShipped();
}看起來合理?但其實這段程式碼揭示了一個問題:訂單在付款前不可能出貨,因此 hasShipped 為 true 時 isPaid 必然為 true,使得表達式中的一部分是冗餘的。正確的寫法應該是:
public boolean isComplete() {
return hasShipped();
}三種明確的狀態#
在實務中,當你加入取消和退款功能,狀態處理的需求會變得更複雜。在此案例中,一個訂單只能處於三種明確的狀態之一:
- In progress(進行中):可以新增或移除商品,不能出貨
- Paid(已付款):不能新增或移除商品,可以出貨
- Shipped(已出貨):完成,不再接受變更
這些狀態至關重要——你需要在執行操作前檢查是否處於預期狀態,並且只能移動到合法的狀態。
如何用狀態思考#
- 提取有意義的表達式到方法中是個很好的開始,但只是起步
- 學習理解狀態機(state machine)。它們並不特別困難,可以視覺化、容易理解和討論
- 用**測試驅動(test-drive)**你的程式碼,釐清有效和無效的狀態與轉換
- 研究 State pattern(狀態模式),搭配 Design by Contract(契約式設計)確保狀態的有效性
如果你的狀態不正確,就有破壞資料的風險。如果你覺得狀態檢查只是雜訊,學習使用工具、程式碼產生、weaving 或 aspect 來隱藏它們。無論選擇哪種方式,用狀態思考會讓你的程式碼更簡潔、更穩健。