定义
允许一个对象在其内部状态改变时,改变它的行为;
行为型
适用场景
- 一个对象存在多个状态(不同状态下行为不同),且状态可相互转换
优点和缺点
优点
- 将不同的状态隔离
- 把各种状态的转换逻辑,分布到State子类中,减少相互间依赖
- 增加新的状态非常简单
缺点
结构
- 环境类角色:也称为上下文,它定义了客户端需要大的接口,内部维护一个当前状态,并负责具体的状态切换;
- 抽象状态角色:定义一个接口,用以封装环境对象中大的特定状态所对应的行为,可以有一个或多个行为。
- 具体状态角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
代码实现
假设我们播放一个视频,一共有四种状态,播放、快进、暂停、停止,这四种状态,有的可以相互切换,有的不行
环境类角色,上下文,缓存一个当前状态,并负责切换状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class VideoContext {
private VideoState videoState;
public VideoState getVideoState() { return videoState; }
public void setVideoState(VideoState videoState) { this.videoState = videoState; this.videoState.setVideoContext(this); }
public void play() { this.videoState.play(); }
public void speed() { this.videoState.speed(); }
public void pause() { this.videoState.pause(); }
public void stop() { this.videoState.stop(); } }
|
抽象状态角色,组合有上下文类,方便子类使用
1 2 3 4 5 6 7 8 9 10 11 12
| public abstract class VideoState { protected VideoContext videoContext;
public void setVideoContext(VideoContext videoContext) { this.videoContext = videoContext; }
public abstract void play(); public abstract void speed(); public abstract void pause(); public abstract void stop(); }
|
具体状态角色
播放状态,可以和另外三种状态进行切换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class PlayState extends VideoState {
@Override public void play() { System.out.println("正常播放视频状态"); }
@Override public void speed() { super.videoContext.setVideoState(new SpeedState()); }
@Override public void pause() { super.videoContext.setVideoState(new PauseState()); }
@Override public void stop() { super.videoContext.setVideoState(new StopState()); } }
|
快进状态,可以和另外三种状态切换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class SpeedState extends VideoState{
@Override public void play() { super.videoContext.setVideoState(new PlayState()); }
@Override public void speed() { System.out.println("快进播放视频状态"); }
@Override public void pause() { super.videoContext.setVideoState(new PauseState()); }
@Override public void stop() { super.videoContext.setVideoState(new StopState()); }
}
|
暂停状态,可以和另外三种状态切换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class PauseState extends VideoState{
@Override public void play() { super.videoContext.setVideoState(new PlayState()); }
@Override public void speed() { super.videoContext.setVideoState(new SpeedState()); }
@Override public void pause() { System.out.println("暂停播放视频状态"); }
@Override public void stop() { super.videoContext.setVideoState(new StopState()); }
}
|
停止状态,只能和播放状态切换,停止的情况下不能快进和暂停
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class StopState extends VideoState{
@Override public void play() { super.videoContext.setVideoState(new PlayState()); }
@Override public void speed() { System.out.println("ERROR, 停止状态不能快进"); }
@Override public void pause() { System.out.println("ERROR,停止状态不能暂停"); }
@Override public void stop() { System.out.println("停止播放视频状态"); }
}
|
测试,视频开始是播放状态,我们有事需要离开一会,可以切换成暂停状态,回来想要快进看,由暂停直接切换到快进状态,看完之后切换到停止状态,从停止状态再切换到快进状态是不允许的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Test {
public static void main(String[] args) { VideoContext videoContext = new VideoContext(); videoContext.setVideoState(new PlayState());
System.out.println("当前状态:"+videoContext.getVideoState().getClass().getSimpleName());
videoContext.pause(); System.out.println("当前状态:"+videoContext.getVideoState().getClass().getSimpleName());
videoContext.speed(); System.out.println("当前状态:"+videoContext.getVideoState().getClass().getSimpleName());
videoContext.stop(); System.out.println("当前状态:"+videoContext.getVideoState().getClass().getSimpleName());
videoContext.speed(); }
}
|
结果:
1 2 3 4 5
| 当前状态:PlayState 当前状态:PauseState 当前状态:SpeedState 当前状态:StopState ERROR, 停止状态不能快进
|
UML类图