代碼執行結果如下圖:
代碼說明
l User類型是環境角色。它的作用一是定義了客戶端感興趣的方法(購買書籍),二是擁有一個狀態實例,它定義了用戶的當前狀態(普通會員、銀會員、黃金會員還是鑽石會員)。
l UserLevel類型是抽象狀態角色。它的作用一是定義了和狀態相關的行為的接口,二是擁有一個環境實例,用於在一定條件下修改環境角色的抽象狀態。
l NormalUser、 SilverUser、GoldUser以及DiamondUser就是具體狀態了。它們都實現了抽象狀態角色定義的接口。
l 為User轉化UserLevel的操作是在各個具體狀態中進行的。在這裡可以看到這種狀態的轉化是有序列的,這樣也只會有前後兩個狀態產生依賴。假設現在的會員系統中是沒有鑽石用戶的,那麼GoldUser的StateCheck()方法中應該是沒有什麼代碼的,即使以後再要加DiamondUser類,我們也只需要修改GoldUser的SateCheck()方法,以根據一定的規則來為環境轉化狀態。
l 在這裡,我們在環境中調用了StateCheck方法,在實際應用中,你可以根據需要在抽象狀態中引入模版方法,對外公開這個模版方法,並且在模版方法中調用行為方法和轉化狀態的方法,當然,具體的行為還是由具體狀態來實現的。
何時采用
l 從代碼角度來說,如果一個類有多種狀態,並且在類內部通過的條件語句判斷的類狀態來實現不同行為時候可以把這些行為單獨封裝為狀態類。
l 從應用角度來說,如果一個對象有多種狀態,如果希望把對象狀態的轉化以及由不同狀態產生的行為交給具體的狀態類去做,那麼可以考慮狀態模式。
實現要點
l 在環境角色中擁有狀態角色的實例。
l 在狀態角色中擁有環境角色的實例用於在具體狀態中修改環境角色的狀態。
l 狀態對象之間的依賴可以通過加載外部配置的轉化規則表等方法來消除。
l 狀態模式和策略模式的主要區別是,前者的行為實現方式是由條件決定的,並且應當能不在客戶端干預的情況下自己遷移到合適的狀態,而後者的行為實現方式是由客戶端選擇的,並且能隨時替換。
注意事項
l 過多的狀態對象可能會增加系統負擔,可以考慮把各種狀態角色實現為無狀態對象的享元,需要保存的額外狀態由環境角色進行統一管理和處理。