設計模式之狀態模式

0x01.定義與類型

  • 定義:容許一個對象在內部狀態改變時,改變它的行爲。
  • 類型:行爲型
  • UML類圖,這個基本實現相似電燈開關那種(0,1)的狀態切換。

state1.png

  • Java實現
/**
 * 狀態上下文
 * 維護一個state實例,這個爲實體當前的狀態
 */
public class Context {

    /**
     * 當前的狀態
     */
    private State state;

    /**
     * 構造函數
     * @param state
     */
    public Context(State state) {
        this.state = state;
    }

    /**
     * 請求狀態
     */
    public void request() {
        state.handler(this);
    }

    //--set get

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }
}

/**
 * 狀態接口
 */
public interface State {

    void handler(Context context);

}

/**
 * 具體的狀態
 */
public class ConcreteStateA implements State {
    @Override
    public void handler(Context context) {
        System.out.println("this is state A.");
        context.setState(new ConcreteStateB());
    }
}

/**
 * 具體的狀態
 */
public class ConcreteStateB implements State {
    @Override
    public void handler(Context context) {
        System.out.println("this is state B.");
        context.setState(new ConcreteStateA());
    }
}
  • 測試與應用
/**
 * 測試與應用
 */
public class Test {

    public static void main(String[] args) {
        //建立狀態上下文
        Context context = new Context(new ConcreteStateA());

        //切換狀態, 這個有點相似電燈的開關狀態
        context.request();
        context.request();
        context.request();
        context.request();
        context.request();
    }
}
  • 輸入日誌
this is state A.
this is state B.
this is state A.
this is state B.
this is state A.
  • 狀態模式中的角色介紹html

    • 上下文環境(Context):它定義了客戶端程序須要的接口並維護一個具體狀態角色的實例,將與狀態相關的操做委託給當前的Concrete State對象來處理。
    • 抽象狀態(State):定義一個接口以封裝使用上下文環境的一個特定狀態的相關的行爲。
    • 具體狀態(Concrete State):實現抽象狀態定義的接口。

0x02.適用場景

  • 一個對象存在多個狀態(不一樣狀態下行爲不一樣),且狀態可相互轉換。
  • 電商訂單狀態扭轉
  • 主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的狀況。把狀態的判斷邏輯轉移到表示不一樣的一系列類當中,能夠把複雜的邏輯判斷簡單化。

0x03.優缺點

1.優勢

  • 狀態模式將與特定狀態相關的行爲局部化,把不一樣的狀態隔離。
  • 把各類狀態的轉換邏輯,分佈到State的子類中,減小相互間的依賴。
  • 全部狀態相關的代碼都在子類中,因此增長新的狀態很是簡單。

2.缺點

  • 狀態多的業務場景緻使類數目增長,系統變複雜。

0x04.狀態模式樣例

假設一個視頻的播放有播放中、暫停、快進和中止等等狀態,使用狀態模式實現這個功能。
  • Java實現
/**
 * 課程狀態上下文
 */
public class CourseVideoContext {

    //當前狀態
    private CourseVideoState courseVideoState;

    //播放
    public final static PlayState PLAY_STATE = new PlayState();

    //中止
    public final static StopState STOP_STATE = new StopState();

    //快進
    public final static SpeedState SPEED_STATE = new SpeedState();

    //暫停
    public final static PauseState PAUSE_STATE = new PauseState();

    public CourseVideoState getCourseVideoState() {
        return courseVideoState;
    }

    public void setCourseVideoState(CourseVideoState courseVideoState) {
        this.courseVideoState = courseVideoState;
        this.courseVideoState.setCourseVideoContext(this);
    }

    public void play() {
        this.courseVideoState.play();
    }

    public void speed() {
        this.courseVideoState.speed();
    }

    public void pause() {
        this.courseVideoState.pause();
    }

    public void stop() {
        this.courseVideoState.stop();
    }
}

/**
 * 狀態
 */
public abstract class CourseVideoState {

    protected CourseVideoContext courseVideoContext;

    public void setCourseVideoContext(CourseVideoContext courseVideoContext) {
        this.courseVideoContext = courseVideoContext;
    }

    public abstract void play();

    public abstract void speed();

    public abstract void pause();

    public abstract void stop();
}

/**
 * 暫停狀態
 */
public class PauseState extends CourseVideoState {

    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
    }

    @Override
    public void pause() {
        System.out.println("暫停播放視頻");
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}

/**
 * 播放狀態
 */
public class PlayState extends CourseVideoState {
    @Override
    public void play() {
        System.out.println("正常播放視頻的狀態");
    }

    @Override
    public void speed() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
    }

    @Override
    public void pause() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}

/**
 * 加速狀態
 */
public class SpeedState extends CourseVideoState  {
    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        System.out.println("快進播放視頻");
    }

    @Override
    public void pause() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
    }

    @Override
    public void stop() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
    }
}

/**
 * 中止狀態
 */
public class StopState extends CourseVideoState  {
    @Override
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    @Override
    public void speed() {
        System.out.println("ERROR 中止狀態不能快進!!!");
    }

    @Override
    public void pause() {
        System.out.println("ERROR 中止狀態不能暫停!!!");
    }

    @Override
    public void stop() {
        System.out.println("中止播放視頻。");
    }
}
  • 測試與應用
/**
 * 測試與應用
 */
public class Test {

    public static void main(String[] args) {
        //狀態上下文
        CourseVideoContext courseVideoContext = new CourseVideoContext();

        //狀態
        courseVideoContext.setCourseVideoState(new PlayState());
        System.out.println("當前狀態:" + courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.pause();
        System.out.println("當前狀態:" + courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.speed();
        System.out.println("當前狀態:" + courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.stop();
        System.out.println("當前狀態:" + courseVideoContext.getCourseVideoState().getClass().getSimpleName());

        courseVideoContext.speed();

    }
}
  • 輸入結果
當前狀態:PlayState
當前狀態:PauseState
當前狀態:SpeedState
當前狀態:StopState
ERROR 中止狀態不能快進!!!
  • UML類圖

state2.png

0x05.相關的設計模式

  • 狀態模式和享元模式

0x06.源碼中的狀態模式

  • javax.Lifecycle

0x07.源碼地址

0x08.推薦閱讀

相關文章
相關標籤/搜索