状态模式
HeadFirst里面讲状态模式举了一个自动售卖机的例子,这本书用来理解设计模式可以说是非常棒的了。
定义
Allow an object to alter its behavior when its internal state changes.The object will appear to change its class. 当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。
类图
图片来自网络
角色结构
State——抽象状态角色:接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。 ConcreteState——具体状态角色:每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。 Context——环境角色:定义客户端需要的接口,并且负责具体状态的切换。
实例
大家都知道一个线程的生命周期,从创建开始,是就绪状态(Runnable)->运行状态(Running)->终止(Terminated),如果在运行状态线程被阻塞,则会进入阻塞状态(Blocked),然后阻塞结束,线程重新进入就绪状态(Runnable)。
图片来源于:https://www.cnblogs.com/ChaosJu/p/4528895.html
- 创建线程状态抽象类
public abstract class ThreadState {
/**
* 环境角色,描述线程此时的状态
*/
protected ThreadContext threadContext;
public void setThreadContext(ThreadContext threadContext) {
this.threadContext = threadContext;
}
/**
* 线程在该状态下的操作
*/
public abstract void handle();
}
- 创建具体的线程状态类,继承抽象类
public class StartState extends ThreadState {
@Override
public void handle() {
System.out.println("线程创建,调用start()方法,状态转变为就绪状态");
// 设置环境对象的状态为下一个就绪状态
super.threadContext.setThreadState(ThreadContext.RUNNABLE);
}
}
public class RunnableState extends ThreadState {
@Override
public void handle() {
System.out.println("线程就绪状态,随时可以启动,同时状态转变为运行状态");
super.threadContext.setThreadState(ThreadContext.RUNNING);
}
}
public class RunningState extends ThreadState {
@Override
public void handle() {
System.out.println("线程为运行状态,正在运行,同时转为下一个终止状态");
super.threadContext.setThreadState(ThreadContext.Terminated);
}
}
public class TerminatedState extends ThreadState {
@Override
public void handle() {
System.out.println("线程已终止");
}
}
- 创建环境状态,描述线程当前的状态,并调用handle方法
public class ThreadContext {
/**
* 创建状态
*/
public static final ThreadState START = new StartState();
/**
* 就绪状态
*/
public static final ThreadState RUNNABLE = new RunnableState();
/**
* 运行状态
*/
public static final ThreadState RUNNING = new RunningState();
/**
* 终止状态
*/
public static final ThreadState Terminated = new TerminatedState();
/**
* 定义线程此时的状态
*/
private ThreadState threadState;
public void setThreadState(ThreadState threadState) {
this.threadState = threadState;
this.threadState.setThreadContext(this);
}
/**
* 线程在该状态下的操作
*/
public void handle() {
this.threadState.handle();
}
}
- 创建测试类
public class Test {
public static void main(String[] args) {
ThreadContext threadContext = new ThreadContext();
threadContext.setThreadState(new StartState());
threadContext.handle();
threadContext.handle();
threadContext.handle();
threadContext.handle();
}
}
- 测试结果为
线程创建,调用start()方法,状态转变为就绪状态
线程就绪状态,随时可以启动,同时状态转变为运行状态
线程为运行状态,正在运行,同时转为下一个终止状态
线程已终止
状态模式的优缺点
优点
- 结构清晰
- 避免了过多的switch…case或者if…else语句的使用,避免了程序的复杂性,提高系统的可维护性。
- 遵循设计原则
- 很好地体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就要增加子类,你要修改状态,你只修改一个子类就可以了。
- 封装性非常好
- 这也是状态模式的基本要求,状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。
缺点
- 类膨胀
使用场景
- 行为随状态改变而改变的场景
- 条件、分支判断语句的替代者
注意事项
- 状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的状态最好不要超过5个。
源代码
版权声明:本文为Planeswalker23所创,转载请带上原文链接,感谢。
文档信息
- 本文作者:Planeswalker23
- 本文链接:https://planeswalker23.github.io/2019/09/18/state/
- 版权声明:本作品系原创,作者保留所有权利,未经作者允许,禁止转载和演绎。