推薦:Java設計模式彙總
狀态模式
定義
當一個對象内在狀态改變時允許其改變行為,這個對象看起來像改變了其類。
類型
行為型。
UML類圖
角色
- 環境(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
好好去理清楚這些代碼的邏輯。
這裡便完成了一個簡單的狀态模式的例子。
适用場景
- 行為随狀态改變而改變的場景。
- 條件、分支語句的代替者。
優點
- 封裝了轉換規則。
- 将所有與某個狀态有關的行為放到一個類中,并且可以友善地增加新的狀态,隻需要改變對象狀态即可改變對象的行為。
- 可以讓多個環境對象共享一個狀态對象,進而減少系統中對象的個數。
- 狀态模式的使用必然會增加系統類和對象的個數。
- 狀态模式的結構與實作都較為複雜,如果使用不當将導緻程式結構和代碼的混亂。
- 狀态模式對"開閉原則"的支援并不太好,對于可以切換狀态的狀态模式,增加新的狀态類需要修改那些負責狀态轉換的源代碼,否則無法切換到新增狀态,而且修改某個狀态類的行為也需修改對應類的源代碼。