1. 程式人生 > >設計模式-狀態模式(25)

設計模式-狀態模式(25)

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的行為邏輯處理 @Override
public 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(); } }

源碼

技術分享圖片

從運行結果看,狀態模式隱藏了狀態的變化過程,狀態的變化引起行為的變化。在外只能看到行為的變化,而不用知道是狀態變化引起的。

優點

  • 結構清晰。
  • 遵循設計原則。
  • 封裝性非常好。

缺點

  • 子類太多,不易管理。

效果

  1. 狀態模式需要對每一個系統可能取得的狀態建立一個狀態類的子類。當系統的狀態發生變化時,系統便改變所選的子類。所有與一個特定的狀態有關的行為都被包裝到一個特定的對象裏面,這使得行為的定義局域化。因為同樣的原因,如果有新的狀態以及它對應的行為需要定義時,可以很方便地通過設立新的子類的方式加到系統裏,不需要改動其他的類。
  2. 由於每一個狀態都被包裝到了類裏面,就可以不必采用過程性的處理方式,不必使用長篇累牘的條件轉移語句。
  3. 使用狀態模式使系統狀態的變化變得很明顯。由於不需要用一些屬性來指明系統所處的狀態,所以就不用擔心修改這些屬性不當造成的錯誤。
  4. 可以在系統的不同部分使用一些相同的狀態類的對象,這種共享對象的辦法與享元模式相符合。事實上,此時這些狀態對象基本上是只有行為而沒有內部狀態的享元。
  5. 雖然狀態模式會造成大量的小型狀態類,但是它可以使程序免於大量的條件轉移語句,實際上使程序更易於維護。
  6. 系統所選的狀態子類均是從一個抽象狀態類或接口繼承而來,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)