一、背景
最近系統的學習一下Java設計模式,下了2本電子書,《設計模式之禪》與《Head First 設計模式》,支持國產嘛,先看《設計模式之禪》,首先說一下對它的感覺,敘述比較簡潔明瞭,舉例很有趣味性、貼切,吸引人,有很多對比的例子(不採用設計模式和採用設計模式),對初學者來說還不錯。有一個小遺憾就是:作者所畫的類圖有時並沒有和代碼對應。今天看到狀態模式了,突然想來記錄點什麼,所以這篇博文就誕生了。
二、狀態分析
還是拿作者的例子——電梯,電梯有四種動作:開門,關門,運行,停止。對應四種狀態:門敞狀態,門閉狀態,運行狀態,停止狀態,它們之間的關係如下:
開門(open) | 關門(close) | 運行(run) | 停止(stop) | |
門敞狀態 | no | ok | no | no |
門閉狀態 | ok | no | ok | ok |
運行狀態 | no | no | no | ok |
停止狀態 | ok | no | ok | no |
三、畫出類圖
纔剛開始學畫類圖了,採用的工具是starUML,如下:
四、代碼
在類圖基礎上,利用starUML自動生成代碼,然後再修改而成了。
1、環境封裝類Context
public class Context { private LiftState liftState; public LiftState getLiftState() { return this.liftState; } public void setListState(LiftState liftState) { liftState.setContext(this); this.liftState = liftState; } public void open() { this.liftState.open(); } public void close() { this.liftState.close(); } public void run() { this.liftState.run(); } public void stop() { this.liftState.stop(); } }
2、狀態抽象類LiftState
public abstract class LiftState { protected Context context; public void setContext(Context _context) { this.context = _context; } public abstract void open(); public abstract void close(); public abstract void run(); public abstract void stop(); }
3、四種狀態類和狀態池類OpenningState,ClosingState,RunningState,StoppingState,StatesPools
(1)OpenningState
public class OpenningState extends LiftState { public void open() { //已經打開了,不做任何操作 } public void close() { //打開狀態,是可以關閉的 System.out.println("關閉電梯..."); super.context.setListState(StatesPool.closingState); } public void run() { //開的時候,當然是不能跑的 } public void stop() { //開的時候,也沒必要停 } }
(2)ClosingState
public class ClosingState extends LiftState { public void open() { //關閉了當然是可以打開的 System.out.println("電梯打開"); super.context.setListState(StatesPool.openningState); } public void close() { //已經關閉了 } public void run() { //關閉當然是可以運行的 System.out.println("電梯運行"); super.context.setListState(StatesPool.runningState); } public void stop() { //關閉也可以停止的 System.out.println("電梯停止"); super.context.setListState(StatesPool.stoppingState); } }
(3)RunningState
public class RunningState extends LiftState { public void open() { //正在運行的時候不能開 } public void close() { //正在運行的時候不能關 } public void run() { //已經在運行了 } public void stop() { //運行時候,當然是可以停的 System.out.println("停止電梯..."); // 改變狀態 super.context.setListState(StatesPool.stoppingState); } }
(4)StoppingState
public class StoppingState extends LiftState { public void open() { //停止狀態下可以打開啦 System.out.println("電梯打開"); super.context.setListState(StatesPool.openningState); } public void close() { } public void run() { //停止狀態下可以繼續運行了 System.out.println("電梯運行"); super.context.setListState(StatesPool.runningState); } public void stop() { } }
(5)StatesPools
public class StatesPool { public static final OpenningState openningState = new OpenningState(); public static final ClosingState closingState = new ClosingState(); public static final RunningState runningState = new RunningState(); public static final StoppingState stoppingState = new StoppingState(); }
4、客戶端調用類Client
public class Client { public static void main(String[] args) { Context context = new Context(); context.setListState(new ClosingState()); context.open(); context.close(); context.run(); context.stop(); context.open(); } }
5、運行結果
電梯打開 關閉電梯... 電梯運行 停止電梯... 電梯打開
五、總結
行爲與狀態有對應關係,狀態的切換伴隨着相應的行爲,都可以用狀態模式了。另外抱怨51cto一句:再做好一點行不行啊,每次貼代碼都要我重新選擇語言,上面貼的代碼都選了n次Java了,就不能幫我記住嗎?
ps:代碼地址http://down.51cto.com/data/1029676