一、概念
1、定义:允许一个对象在其内部状态改变时,改变它的行为。状态模式允许对象再内部状态改变时改变它的行为,对象看起来好像修改了它的类。前半句话是说,这个模式将状态封装成了独立的类,并且将动作委托到当前状态的对象。行为会随着内部状态的改变而改变,糖果机投入前后的内部状态是不一样的。后半句话是说,以应用层视角来看,你使用的对象能够完全改变它的行为,你会觉得这个对象可能是从别的类实例化而来的,但实际上是引用不同状态来造成l类被改变的假象。
当控制一个对象状态转换的过程比较复杂的时候,可以把状态的判断逻辑转移到表示不同状态的一系列类当中,把复杂的判断逻辑简化,可以扩展到不同的类当中,扩展状态也相对容易。
2、类型:行为型
3、适用场景
- 一个对象存在多个状态(不同状态下的行为不同,要看具体场景),且状态可以相互转换,在不同状态中判断是否可以转换到目标状态上
4、优缺点
- 优点
- 将不同的状态隔离
- 把各种状态的转换逻辑,分布到State的子类中,减少相互依赖
- 增加新的状态也简单
- 缺点
- 状态多的场景倒是类数目增加,系统变复杂
二、Coding
1、HeadFirst例子
State
:状态接口,定义了根据不同状态进行不同处理的接口,用来封装与上下文的一个特定状态所对应的行为ConcreteState
:具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理,上文即环境Context
:持有表示当前状态的ConcreteState
角色。此外,它还定义了供外部调用者使用State
模式的接口
2、视频场景
场景:网站的课程视频有暂停、播放、快进、停止,停止的时候无法快进,停止的状态转换成快进的时候需要做一层校验
//课程状态抽象类
public abstract class CourseVideoState {
protected CourseVideoContext courseVideoContext;
public void setCourseVideoContext(CourseVideoContext courseVideoContext) {
this.courseVideoContext = courseVideoContext;
}
//四种状态,对应四种状态类,来继承CourseState抽象类
public abstract void play();
public abstract void speed();
public abstract void pause();
public abstract void stop();
}
//视频上下文Context
public class CourseVideoContext {
//上下文组合课程视频的状态
private CourseVideoState courseVideoState;
//直接new成final,可以通过享元模式来共享同一个对象,所以声明为final
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;
//把自己设置成courseVideoState的上下文,这里是关键!!!
this.courseVideoState.setCourseVideoContext(this);
}
//环境(上下文)想要play,直接调用状态的play
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 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 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 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();
System.out.println("当前状态:"+courseVideoContext.getCourseVideoState().getClass().getSimpleName());
}
}
当前状态:PlayState
当前状态:PauseState
当前状态:SpeedState
当前状态:StopState
ERROR!停止状态不能快进
当前状态:StopState
debug一下
上下文中这一句很关键,把this状态设置到了上一行的课程视频状态中,这样的上下文就是最新的上下文了