文章目录
一、状态模式简介
二、状态模式适用场景
三、状态模式优缺点
四、状态模式相关设计模式
五、状态模式代码示例
1、状态类父类
2、播放状态类
3、暂停状态类
4、快进状态类
5、停止状态类
6、上下文控制类
7、测试
一、状态模式简介
状态模式 : 允许 对象 在 内部状态 改变时 , 改变它的行为 ;
一个对象 , 如果其 内部状态改变 , 其 行为也需要进行改变 ; 如果其行为不需要改变 , 也可以只 控制 该对象的状态 的 互相转换 ;
当控制一个对象 , 其状态转换过程比较复杂时 , 将 状态判断逻辑 , 转到代表不同状态的一系列类中 ;
如 : 引入 视频播放 的业务场景 , 播放器有 初始状态 , 播放状态 , 暂停状态 , 停止状态 , 快进状态 等多种状态 , 将这些 状态 都封装到 代表不同状态的类 中 , 可以将复杂的判断逻辑简化 , 将这些 逻辑 扩展到不同的状态类中 ;
状态模式类型 : 行为型 ;
二、状态模式适用场景
状态模式适用场景 : 一个对象 , 存在多个状态 , 状态可以相互转换 ; 不同状态下 , 行为不同 ;
不同状态下 , 行为不同的示例 , 如 :
购买物品 , 将物品放入购物车并生成订单 , 可以进行付款 ; 如果 订单 超过 24 小时后 , 被关闭订单 , 此时订单取消 , 无法付款 ;
电梯运行时 , 不能开门 ; 电梯停止后 , 才能开门 ;
三、状态模式优缺点
状态模式优点 :
可以将 不同的状态 隔离 ; 每个状态都是一个单独的类 ;
可以将 各种状态 的 转换逻辑 , 分布到 状态 的子类中 , 减少相互依赖 ;
增加 新状态 , 操作简单 ;
状态模式缺点 :
如果 状态数量 比较多 , 状态类 的 数量会增加 , 业务场景系统变得很复杂 ; 如果业务中某个对象由几十上百个状态 , 就会很复杂 , 这时就需要对状态进行拆分处理 ;
四、状态模式相关设计模式
状态模式 与 享元模式 , 可以配合在一起使用 , 可以使用享元模式 , 在多个上下文中 , 共享状态实例 ;
五、状态模式代码示例
业务场景 :
视频播放器 , 有 : 暂停 , 播放 , 快进 , 停止 , 四个状态 ;
在 停止 状态下 , 无法快进 , 如果当前是 停止 状态 , 此时要转为 快进 状态 , 需要进行校验 ;
如果不使用 状态模式 , 则需要进行 if else 判断 ;
如果使用 状态模式 , 就很容易实现 ;
状态类 :
定义状态父类抽象类 , 抽象方法是各个状态对应的方法 ;
定义状态子类 , 每个状态对应一个子类对象 ;
上下文类 :
在该类中封装 所有的状态实例 , 以及定义 状态改变方法 ;
封装当前状态类 , 状态改变方法 调用时 , 实际上调用的是 当前状态类的 对应方法 ;
1、状态类父类
package state; /** * 视频状态 父类 * 所有的视频状态 , 都要继承该类 */ public abstract class VedioState { /** * 视频播放上下文 * 声明为 protected , 子类可以拿到该成员变量 */ protected VedioContext vedioContext; public void setVedioContext(VedioContext vedioContext) { this.vedioContext = vedioContext; } /** * 播放 * 对应播放状态 */ public abstract void play(); /** * 停止 * 对应停止状态 */ public abstract void pause(); /** * 快进 * 对应快进状态 */ public abstract void speed(); /** * 停止 * 对应停止状态 */ public abstract void stop(); }
2、播放状态类
package state; /** * 视频的播放状态 * 可以进行 快进 , 暂停 , 停止 操作 */ public class PlayState extends VedioState{ @Override public void play() { System.out.println("正常播放视频"); } /** * 暂停时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 暂停 的状态即可 */ @Override public void pause() { super.vedioContext.setVedioState(VedioContext.PAUSE_STATE); } /** * 快进时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 快进 的状态即可 */ @Override public void speed() { super.vedioContext.setVedioState(VedioContext.SPEED_STATE); } /** * 停止时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 停止 的状态即可 */ @Override public void stop() { super.vedioContext.setVedioState(VedioContext.STOP_STATE); } }
3、暂停状态类
package state; /** * 视频暂停状态 * 暂停状态 可以 切换到 播放 , 快进 , 停止 状态 */ public class PauseState extends VedioState{ /** * 播放时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 播放 的状态即可 */ @Override public void play() { super.vedioContext.setVedioState(VedioContext.PLAY_STATE); } /** * 暂停时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 暂停 的状态即可 */ @Override public void pause() { System.out.println("暂停播放视频"); } /** * 快进时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 快进 的状态即可 */ @Override public void speed() { super.vedioContext.setVedioState(VedioContext.SPEED_STATE); } /** * 停止时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 停止 的状态即可 */ @Override public void stop() { super.vedioContext.setVedioState(VedioContext.STOP_STATE); } }
4、快进状态类
package state; /** * 视频快进状态 * 快进状态下 , 可以进行 播放 , 暂停 , 停止操作 */ public class SpeedState extends VedioState{ /** * 播放时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 播放 的状态即可 */ @Override public void play() { super.vedioContext.setVedioState(VedioContext.PLAY_STATE); } /** * 暂停时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 暂停 的状态即可 */ @Override public void pause() { System.out.println("快进播放视频"); } /** * 快进时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 快进 的状态即可 */ @Override public void speed() { super.vedioContext.setVedioState(VedioContext.SPEED_STATE); } /** * 停止时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 停止 的状态即可 */ @Override public void stop() { super.vedioContext.setVedioState(VedioContext.STOP_STATE); } }
5、停止状态类
package state; /** * 视频的停止状态 * 可以进行 播放 操作 * 不能进行 快进 , 暂停 操作 */ public class StopState extends VedioState{ /** * 播放时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 播放 的状态即可 */ @Override public void play() { super.vedioContext.setVedioState(VedioContext.PLAY_STATE); } /** * 不能暂停 */ @Override public void pause() { System.out.println("停止状态不能暂停"); } /** * 不能快进 */ @Override public void speed() { System.out.println("停止状态不能快进"); } /** * 停止时 , 只需要调用 PlayState 父类 VedioState 的上下文 VedioContext * 将上下文 VedioContext 中的状态 , 设置为 停止 的状态即可 */ @Override public void stop() { System.out.println("停止播放视频"); } }
6、上下文控制类
package state; /** * 使用享元模式 , 共享同一个对象 * * 上下文也有 play , pause , speed , stop 等状态 * 执行这些方法时 , 调用状态的相应方法 */ public class VedioContext { /** * 当前的状态 */ private VedioState mVedioState; public final static PlayState PLAY_STATE = new PlayState(); public final static PauseState PAUSE_STATE = new PauseState(); public final static SpeedState SPEED_STATE = new SpeedState(); public final static StopState STOP_STATE = new StopState(); public VedioState getVedioState() { return mVedioState; } /** * 将传入的 VedioState , 赋值给当前的 VedioState mVedioState 成员 * 除此之外 , 还要设置 VedioState 的上下文 , 即该类本身 * 将当前的环境 VedioContext , 通知到各个状态实现类 * @param mVedioState */ public void setVedioState(VedioState mVedioState) { this.mVedioState = mVedioState; this.mVedioState.setVedioContext(this); } public void play() { this.mVedioState.play(); } public void pause() { this.mVedioState.pause(); } public void speed() { this.mVedioState.speed(); } public void stop() { this.mVedioState.stop(); } }
7、测试
package state; public class Main { public static void main(String[] args) { VedioContext vedioContext = new VedioContext(); vedioContext.setVedioState(VedioContext.PLAY_STATE); System.out.println("当前视频状态 : " + vedioContext.getVedioState().getClass().getSimpleName()); vedioContext.pause(); System.out.println("当前视频状态 : " + vedioContext.getVedioState().getClass().getSimpleName()); vedioContext.speed(); System.out.println("当前视频状态 : " + vedioContext.getVedioState().getClass().getSimpleName()); vedioContext.stop(); System.out.println("当前视频状态 : " + vedioContext.getVedioState().getClass().getSimpleName()); vedioContext.speed(); System.out.println("当前视频状态 : " + vedioContext.getVedioState().getClass().getSimpleName()); } }
执行结果 :
————————————————