Java與設計模式-狀態模式
概念:狀態模式把所研究的對象的行為包裝在不同的狀態對象裏。每個狀態對象都屬於一個抽象狀態類的一個子類。
狀態模式的意圖是讓一個對象在其內部狀態改變的時候。其行為也隨之改變,也就是不同狀態相應不同的行為。狀態模式的示意性類圖例如以下所看到的:
UML類圖:Context:能夠理解成控制類
State是狀態接口
ConcreteStateA和ConcreteStateB能夠覺得是接口的實現,也就是詳細的狀態實現類。
使用場景:對象的狀態決定對象的行為,在執行時依據狀態動態調整對象的行為。
代碼中有復雜的if else推斷。且這些分支推斷和狀態有關系。
實際場景:(1)電視開關機狀態,電視開機狀態下才幹夠進行各種操作,關機狀態下,不能進行各項操作。
(2)WIFI狀態,WIFI開狀態下能夠連接WIFI,關閉狀態不可進行操作。
(3)登錄狀態,這個在開發中較為經常使用。一般在進入系統實現分享轉發等操作時要先推斷用戶的登錄狀態,若已經登錄則可進行操作。否則提示用戶登錄。
我們來實現場景1.
首先創建一個狀態接口(相應UML類圖中的State接口):
package com.state.demo; public interface TvState { /** * 電視狀態的接口,裏面提供四種方法 */ void nextChanel(); void preChanel(); void turnUp(); void turnDown(); }
接下來兩個實現類(相應UML類圖中ConcreteStateA):
package com.state.demo; public class PowerOnState implements TvState { /** * 開機狀態下,遙控器button有效 */ @Override public void nextChanel() { System.out.println("---------下一頻道-----------------------"); } @Override public void preChanel() { System.out.println("---------上一頻道-----------------------"); } @Override public void turnUp() { System.out.println("---------音量增大-----------------------"); } @Override public void turnDown() { System.out.println("---------音量減小-----------------------"); } }
實現類2(相應UML類圖中ConcreteStateB):
package com.state.demo; public class PowerOffState implements TvState { /** * 關機狀態下。全部button無效 */ @Override public void nextChanel() { System.out.println("---------關機狀態不可用。請先開機-----------------------"); } @Override public void preChanel() { System.out.println("---------關機狀態不可用,請先開機-----------------------"); } @Override public void turnUp() { System.out.println("---------關機狀態不可用。請先開機-----------------------"); } @Override public void turnDown() { System.out.println("---------關機狀態不可用。請先開機-----------------------"); } }
接下來控制類(相應UML類圖中Context):
package com.state.demo; public class TvController { TvState tvState=null; public void setTvState(TvState tvState) { this.tvState = tvState; } /** * 開機 */ public void turnOnTv(){ setTvState(new PowerOnState()); System.out.println("--------開機啦---------------"); } /** * 關機 */ public void turnOffTv(){ setTvState(new PowerOffState()); System.out.println("--------關機啦---------------"); } /** * 下一頻道 */ public void nextChanel(){ tvState.nextChanel(); } public void preChanel(){ tvState.preChanel(); } public void turnUp(){ tvState.turnUp(); } public void turnDown(){ tvState.turnDown(); } }
最後,編寫一個測試類,測試以上代碼:
package com.state.demo; public class TestClass { public static void main(String[] args) { TvController tvController=new TvController();//創建一個控制類 tvController.turnOnTv();//首先開機 tvController.nextChanel(); tvController.turnDown(); tvController.turnOffTv();//關機 tvController.turnDown();//關機後功能不再提供 } }
執行實比例如以下:
這裏有些邏輯小問題,就是在已經開機的狀態下,用戶再次調用開機要進行提示。這時我們能夠在控制類中增加例如以下代碼;
package com.state.demo; public class TvController { private boolean isTvOn=false; TvState tvState=null; public void setTvState(TvState tvState) { this.tvState = tvState; } /** * 開機 */ public void turnOnTv(){ if(!isTvOn){ isTvOn=true; setTvState(new PowerOnState()); System.out.println("--------開機啦---------------"); }else{ isTvOn=true; System.out.println("--------已經開機了,不要再按了---------------"); } } /** * 關機 */ public void turnOffTv(){ if(isTvOn){ isTvOn=false; setTvState(new PowerOffState()); System.out.println("--------關機啦---------------"); }else{ isTvOn=false; System.out.println("-------已經關機啦,不要再按了---------------"); } } /** * 下一頻道 */ public void nextChanel(){ tvState.nextChanel(); } public void preChanel(){ tvState.preChanel(); } public void turnUp(){ tvState.turnUp(); } public void turnDown(){ tvState.turnDown(); } }
做一個開機標識,每次調用方法之前進行推斷就可以。
這時再次執行測試類:
package com.state.demo; public class TestClass { public static void main(String[] args) { TvController tvController=new TvController();//創建一個控制類 tvController.turnOnTv();//首先開機 tvController.turnOnTv();//首先開機 tvController.nextChanel(); tvController.turnDown(); tvController.turnOffTv();//關機 tvController.turnOffTv();//關機 tvController.turnDown();//關機後功能不再提供 } }
執行例如以下:
總結:控制類持有系統狀態,但控制類不直接處理行為,行為在狀態的實現類中實現;
用戶直接操作控制類,直接和控制類交互,不直接操作狀態實現類,這樣就有一個職責的分離,有利於系統維護。
喜歡的朋友請關註我,謝謝。
Java與設計模式-狀態模式