设计模式状态模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式状态模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )相关的知识,希望对你有一定的参考价值。
文章目录
一、状态模式简介
状态模式 : 允许 对象 在 内部状态 改变时 , 改变它的行为 ;
一个对象 , 如果其 内部状态改变 , 其 行为也需要进行改变 ; 如果其行为不需要改变 , 也可以只 控制 该对象的状态 的 互相转换 ;
当控制一个对象 , 其状态转换过程比较复杂时 , 将 状态判断逻辑 , 转到代表不同状态的一系列类中 ;
如 : 引入 视频播放 的业务场景 , 播放器有 初始状态 , 播放状态 , 暂停状态 , 停止状态 , 快进状态 等多种状态 , 将这些 状态 都封装到 代表不同状态的类 中 , 可以将复杂的判断逻辑简化 , 将这些 逻辑 扩展到不同的状态类中 ;
状态模式类型 : 行为型 ;
二、状态模式适用场景
状态模式适用场景 : 一个对象 , 存在多个状态 , 状态可以相互转换 ; 不同状态下 , 行为不同 ;
不同状态下 , 行为不同的示例 , 如 :
购买物品 , 将物品放入购物车并生成订单 , 可以进行付款 ; 如果 订单 超过 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());
}
}
执行结果 :
以上是关于设计模式状态模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )的主要内容,如果未能解决你的问题,请参考以下文章
设计模式简单工厂模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
设计模式迭代器模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
设计模式中介者模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
设计模式组合模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )