状态模式(State Pattern)也被称为状态机模式(State Machine Pattern),是在 GoF 23 种设计模式中定义了的行为型模式。
在状态模式 类的行为是基于它的状态改变的。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。状态模式 对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
~
本篇文章内容包括:关于状态模式、状态模式 Demo
文章目录
- 一、关于状态模式
- 1、关于状态模式
- 2、关于状态模式的构成
- 3、关于状态模式UML
- 4、关于状态模式的应用场景
- 5、关于状态模式的优缺点
- 二、状态模式 Demo
- 1、Demo 设计
- 2、Demo 实现
- 3、Demo 测试
一、关于状态模式
1、关于状态模式
状态模式(State Pattern)也被称为状态机模式(State Machine Pattern),是在 GoF 23 种设计模式中定义了的行为型模式。
在状态模式 类的行为是基于它的状态改变的。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。状态模式 对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
2、关于状态模式的构成
状态模式主要包含以下 3 种角色:
- 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换;
- 抽象状态(State)角色:定义一个接口,用以封装环境中的特定状态所对应的行为,可以有一个或多个行为;
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
3、关于状态模式UML
4、关于状态模式的应用场景
通常在以下情况下可以考虑使用状态模式。
- 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
- 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。
5、关于状态模式的优缺点
# 状态模式优点
- 可以将不同的状态隔离;
- 每个状态都是一个单独的类;
- 可以将各种状态的转换逻辑,分布到状态的子类中,减少相互依赖;
- 增加新状态,操作简单;
# 状态模式缺点
- 如果状态数量比较多,状态类的数量会增加,业务场景系统变得很复杂;
- 如果业务中某个对象由几十上百个状态,就会很复杂,这时就需要对状态进行拆分处理。
二、状态模式 Demo
1、Demo 设计
我们此处可以设计一个多线程的状态转换程序,多线程存在 新建、就绪、运行、阻塞和死亡状态。各种状态当遭到相关方法调用/事件触发时会向其他状态转换。
2、Demo 实现
# ThreadContext 环境类(Context)角色
public class ThreadContext {
private ThreadState state;
ThreadContext() {
state = new New();
}
public ThreadState getState() {
return state;
}
public void setState(ThreadState state) {
this.state = state;
}
public void start() {
((New) state).start(this);
}
public void getCpu() {
((Runnable) state).getCpu(this);
}
public void suspend() {
((Running) state).suspend(this);
}
public void stop() {
((Running) state).stop(this);
}
public void resume() {
((Blocked) state).resume(this);
}
}
# ThreadState 抽象状态(State)角色
public abstract class ThreadState {
/**
* 状态名
*/
protected String stateName;
}
# 新建 New 具体状态(Concrete State)角色
public class New extends ThreadState {
public New() {
stateName = "新建";
System.out.println("线程状态:新建");
}
public void start(ThreadContext context) {
System.out.println("调用 start 方法");
if ("新建".equals(stateName)) {
context.setState(new Runnable());
} else {
System.out.println("当前线程不是 New 状态,无法调用 start");
}
}
}
# 就绪 Runnable 具体状态(Concrete State)角色
public class Runnable extends ThreadState{
public Runnable() {
stateName = "就绪";
System.out.println("线程状态:就绪");
}
public void getCpu(ThreadContext context) {
System.out.println("调用 getCpu 方法");
if ("就绪".equals(stateName)) {
context.setState(new Running());
} else {
System.out.println("当前线程不是 就素 状态,无法调用获取 '获取CPU' 的方法");
}
}
}
# 运行 Running 具体状态(Concrete State)角色
public class Running extends ThreadState {
public Running() {
stateName = "运行";
System.out.println("线程状态:运行");
}
/**
* 挂起
* @param context ThreadContext
*/
public void suspend(ThreadContext context) {
System.out.println("调用 suspend 方法");
if ("运行".equals(stateName)) {
context.setState(new Blocked());
} else {
System.out.println("当前线程不是 运行 状态,无法调用获取 '挂起' 的方法");
}
}
/**
* 停止
* @param context ThreadContext
*/
public void stop(ThreadContext context) {
System.out.println("调用 stop 方法");
if ("运行".equals(stateName)) {
context.setState(new Dead());
} else {
System.out.println("当前线程不是 运行 状态,无法调用获取 '停止' 的方法");
}
}
}
# 阻塞 Blocked 具体状态(Concrete State)角色
public class Blocked extends ThreadState {
public Blocked() {
stateName = "阻塞";
System.out.println("线程状态:阻塞");
}
/**
* 状态恢复
* @param context ThreadContext
*/
public void resume(ThreadContext context) {
System.out.println("调用 resume 方法");
if ("阻塞".equals(stateName)) {
context.setState(new Runnable());
} else {
System.out.println("当前线程不是 阻塞 状态,无法调用获取 '状态恢复' 的方法");
}
}
}
# 死亡 Dead 具体状态(Concrete State)角色
public class Dead extends ThreadState {
public Dead() {
stateName = "死亡";
System.out.println("线程状态:死亡");
}
}
3、Demo 测试
public class Client {
public static void main(String[] args) {
ThreadContext context = new ThreadContext();
context.start();
context.getCpu();
context.suspend();
context.resume();
context.getCpu();
context.stop();
}
}