設計模式-狀態模式(25)
阿新 • • 發佈:2018-04-26
java 可能 strac 以及 main 沒有 bject 角色 mage
定義
狀態模式(State Pattern)又稱為狀態對象模式,該模式允許一個對象在其內部狀態改變的時候改變行為。
英文:Allow an object to alert its behavior when its internal state changes.The object will appear to change its class.
翻譯:允許一個對象內在狀態發生改變時改變行為,使得這個對象看起來像改變了類型。
狀態模式的核心是封裝,狀態的變更引起行為的變動,從外部看來就好像該對象對應的類發生改變一樣。
角色
抽象狀態(State)角色:該角色用以封裝環境的一個特定的狀態所對應的行為。
具體狀態(Concrete State)角色:該角色實現環境的某一個狀態所對應的行為。
環境(Context)角色:該角色定義客戶端需要的接口,並負責具體狀態的切換。它會保留一個具體狀態類的實例,該實例給出環境對象的現有狀態。
/** * 抽象狀態 */ public abstract class State { //定義一個環境角色 protected Context context; //設置環境 public void setContext(Context context){ this.context = context; }//抽象行為 public abstract void handle(); } /** * 具體狀態 */ public class ConcreteState1 extends State { //狀態1的行為邏輯處理 @Override public void handle() { System.out.println("行為一的邏輯處理"); } } /** * 具體狀態2 */ public class ConcreteState2 extends State { //狀態2的行為邏輯處理 @Overridepublic void handle() { System.out.println("行為二的邏輯處理"); } } /** * 環境角色 */ public class Context { //定義狀態 public static State STATE1 = new ConcreteState1(); public static State STATE2 = new ConcreteState2(); //當前狀態 private State currentState; //獲取當前狀態 public State getCurrentState() { return currentState; } //設置當前狀態 public void setCurrentState(State currentState) { this.currentState=currentState; //設置狀態的環境 currentState.setContext(this); } //行為委托 public void handle1(){ //切換到狀態1 this.setCurrentState(STATE1); this.currentState.handle(); } //行為委托 public void handle2(){ //切換到狀態2 this.setCurrentState(STATE2); this.currentState.handle(); } } public class Main { public static void main(String[] args) { //定義環境角色 Context context = new Context(); //執行行為 context.handle1(); context.handle2(); } }
源碼
從運行結果看,狀態模式隱藏了狀態的變化過程,狀態的變化引起行為的變化。在外只能看到行為的變化,而不用知道是狀態變化引起的。
優點
- 結構清晰。
- 遵循設計原則。
- 封裝性非常好。
缺點
- 子類太多,不易管理。
效果
- 狀態模式需要對每一個系統可能取得的狀態建立一個狀態類的子類。當系統的狀態發生變化時,系統便改變所選的子類。所有與一個特定的狀態有關的行為都被包裝到一個特定的對象裏面,這使得行為的定義局域化。因為同樣的原因,如果有新的狀態以及它對應的行為需要定義時,可以很方便地通過設立新的子類的方式加到系統裏,不需要改動其他的類。
- 由於每一個狀態都被包裝到了類裏面,就可以不必采用過程性的處理方式,不必使用長篇累牘的條件轉移語句。
- 使用狀態模式使系統狀態的變化變得很明顯。由於不需要用一些屬性來指明系統所處的狀態,所以就不用擔心修改這些屬性不當造成的錯誤。
- 可以在系統的不同部分使用一些相同的狀態類的對象,這種共享對象的辦法與享元模式相符合。事實上,此時這些狀態對象基本上是只有行為而沒有內部狀態的享元。
- 雖然狀態模式會造成大量的小型狀態類,但是它可以使程序免於大量的條件轉移語句,實際上使程序更易於維護。
- 系統所選的狀態子類均是從一個抽象狀態類或接口繼承而來,Java語言的特性使得在Java語言中使用狀態模式較為安全,多態性是狀態模式的核心。
使用場景
- 對象的行為依賴於它所處的狀態,即行為隨狀態改變而改變的場景。
- 對象在某個方法中依賴於一重或多重條件分支語句,此時可以使用狀態模式將每一個分支語句都包裝到一個單獨的類中,使得這些條件分支語句能夠以類的方式獨立存在和演化。如此,維護這些獨立的類就不會影響到系統的其他部分。
/** * 頻道(抽象狀態) */ public interface Channel { //播放頻道中的節目 public void display(); } /** * 具體狀態 */ public class CCTV1 implements Channel { @Override public void display() { System.out.println("CCTV1正在播放新聞聯播"); } } /** * 具體狀態 */ public class CCTV2 implements Channel { @Override public void display() { System.out.println("CCTV2正在播放動物世界"); } } /** * 具體狀態 */ public class CCTV6 implements Channel { @Override public void display() { System.out.println("CCTV6正在播放電影"); } } /** * 電視--環境角色 */ public class TV { private Channel channel1 = new CCTV1(); private Channel channel2 = new CCTV2(); private Channel channel6 = new CCTV6(); //當前頻道 private Channel curChanel; public Channel getCurChanel() { return curChanel; } public void setCurChanel(Channel curChanel) { this.curChanel = curChanel; } public void displayCCTV1(){ this.setCurChanel(channel1); this.curChanel.display(); } public void displayCCTV2(){ this.setCurChanel(channel2); this.curChanel.display(); } public void displayCCTV6(){ this.setCurChanel(channel6); this.curChanel.display(); } } public class Main { public static void main(String[] args) { TV tv = new TV(); tv.displayCCTV1(); System.out.println("CCTV1播放廣告"); tv.displayCCTV2(); System.out.println("就是想換臺"); tv.displayCCTV6(); } }
源碼
設計模式-狀態模式(25)