天天看點

設計模式-狀态模式(State Pattern)

推薦:​​Java設計模式彙總​​

狀态模式

定義

當一個對象内在狀态改變時允許其改變行為,這個對象看起來像改變了其類。

類型

行為型。

UML類圖

設計模式-狀态模式(State Pattern)

角色

  • 環境(Context)角色:環境角色含有狀态角色的對象,并且可以處理一些請求,這些請求最終産生的響應會與狀态相關。
  • 狀态(State)角色:狀态角色定義了每一個狀态的行為接口,這些行為将會在​

    ​Context​

    ​中得以使用。
  • 具體狀态(ConcreteState)角色:實作了相關行為的具體狀态類。

例子

我們看課程視訊時,可以播放、加速、暫停視訊和停止視訊(退出了觀看課程視訊界面)。

  • 當課程視訊處于播放狀态時,課程視訊可以正常播放、加速、暫停、停止。
  • 當課程視訊處于加速狀态時,課程視訊可以正常播放、加速、暫停、停止。
  • 當課程視訊處于暫停狀态時,課程視訊可以正常播放、加速、暫停、停止。
  • 當課程視訊處于停止狀态時,課程視訊可以正常播放、停止,而不能正常加速、暫停。

不用糾結這些規則,隻是為了說明​

​當一個對象内在狀态改變時允許其改變行為​

​。

CourseVideoContext類(環境角色),含有狀态角色的對象​

​courseVideoState​

​。

package com.kaven.design.pattern.behavioral.state;

public class CourseVideoContext {

    private CourseVideoState courseVideoState;
    public final static PlayState PLAY_STATE = new PlayState();
    public final static SpeedState SPEED_STATE = new SpeedState();
    public final static PauseState PAUSE_STATE = new PauseState();
    public final static StopState STOP_STATE = new StopState();

    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();
    }
}      

CourseVideoState類(狀态角色),定義了每一個狀态的行為接口,這些行為将會在​

​Context​

​中得以使用,從CourseVideoContext類代碼也可以看出來。

package com.kaven.design.pattern.behavioral.state;

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();
}      

PlayState類(具體狀态角色),播放狀态類,繼承了CourseVideoState類,實作了對應的行為(根據上面說的規則)。

package com.kaven.design.pattern.behavioral.state;

public class PlayState extends CourseVideoState{
    public void play() {
        System.out.println("正常播放課程視訊狀态");
    }

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

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

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

SpeedState類(具體狀态角色),加速狀态類,繼承了CourseVideoState類,實作了對應的行為(根據上面說的規則)。

package com.kaven.design.pattern.behavioral.state;

public class SpeedState extends CourseVideoState {
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    public void speed() {
        System.out.println("快進播放課程視訊狀态");
    }

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

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

PauseState類(具體狀态角色),暫停狀态類,繼承了CourseVideoState類,實作了對應的行為(根據上面說的規則)。

package com.kaven.design.pattern.behavioral.state;

public class PauseState extends CourseVideoState {
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

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

    public void pause() {
        System.out.println("暫停播放課程視訊狀态");
    }

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

StopState類(具體狀态角色),停止狀态類,繼承了CourseVideoState類,實作了對應的行為(根據上面說的規則)。

package com.kaven.design.pattern.behavioral.state;

public class StopState extends CourseVideoState {
    public void play() {
        super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
    }

    public void speed() {
        System.out.println("ERROR 停止狀态不能快進");
    }

    public void pause() {
        System.out.println("ERROR 停止狀态不能暫停");
    }

    public void stop() {
        System.out.println("停止播放課程視訊狀态");
    }
}      

應用層代碼:

package com.kaven.design.pattern.behavioral.state;

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();
        System.out.println("目前狀态:"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());
    }
}      

輸出:

目前狀态:PlayState
目前狀态:PauseState
目前狀态:SpeedState
目前狀态:StopState
ERROR 停止狀态不能快進
目前狀态:StopState      

好好去理清楚這些代碼的邏輯。

這裡便完成了一個簡單的狀态模式的例子。

适用場景

  • 行為随狀态改變而改變的場景。
  • 條件、分支語句的代替者。

優點

  • 封裝了轉換規則。
  • 将所有與某個狀态有關的行為放到一個類中,并且可以友善地增加新的狀态,隻需要改變對象狀态即可改變對象的行為。
  • 可以讓多個環境對象共享一個狀态對象,進而減少系統中對象的個數。
  • 狀态模式的使用必然會增加系統類和對象的個數。
  • 狀态模式的結構與實作都較為複雜,如果使用不當将導緻程式結構和代碼的混亂。
  • 狀态模式對"開閉原則"的支援并不太好,對于可以切換狀态的狀态模式,增加新的狀态類需要修改那些負責狀态轉換的源代碼,否則無法切換到新增狀态,而且修改某個狀态類的行為也需修改對應類的源代碼。