状态模式
状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。
它主要用来解决对象在多种状态转换时,需要对 输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换
当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类
概括:允许一个对象在其内部状态发生改变时改变其行为能力。
核心:改变一个对象的状态时,输出不同的行为。
模式结构
- 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
类图
优缺点
优点:
- 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
- 单一职责原则。 将与特定状态相关的代码放在单独的类中。
- 开闭原则。 无需修改已有状态类和上下文就能引入新状态。
- 方便维护。将容易产生问题的if-else语句删除了,如果把每个状态的行为都放到一
个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多if-else语句,而且容易出错。
缺点:
- 如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作。
- 状态模式的使用必然会增加系统的类与对象的个数,容易造成类爆炸。
- 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
应用场景
- 当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式。
- 如果某个类需要根据成员变量的当前值改变自身行为, 从而需要使用大量的条件语句时, 可使用该模式。
- 当相似状态和基于条件的状态机转换中存在许多重复代码时, 可使用状态模式。
- 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。
示例代码
使用状态模式模拟线程切换场景
public class BlockedState extends ThreadState {
public BlockedState(Status stateName) {
System.out.println("线程处于阻塞状态");
this.stateName = stateName;
}
public void resume(ThreadContext context){
if (stateName == Status.BLOCKED){
System.out.println("线程就绪:");
context.setState(new RunnableState(Status.RUNNABLE));
}
else System.out.println("不是阻塞状态,无法设置就绪状态");
}
}
public class DeadState extends ThreadState{
public DeadState(Status stateName){
System.out.println("线程处于结束状态");
this.stateName = stateName;
}
}
public class NewState extends ThreadState {
public NewState(Status stateName){
System.out.println("线程处于新建状态");
this.stateName = stateName;
}
public void start(ThreadContext context){
if (stateName == Status.NEW){
System.out.println("线程启动:");
context.setState(new RunnableState(Status.RUNNABLE));
}
else System.out.println("已经是新建状态");
}
}
public class RunnableState extends ThreadState {
public RunnableState(Status stateName){
System.out.println("线程处于就绪状态");
this.stateName = stateName;
}
public void getCpu(ThreadContext context){
if (stateName == Status.RUNNABLE){
System.out.println("线程开始运行:");
context.setState(new RunningState(Status.RUNNING));
}
else System.out.println("已经是就绪状态");
}
}
public class RunningState extends ThreadState {
public RunningState(Status stateName){
System.out.println("线程处于运行状态");
this.stateName = stateName;
}
public void stop(ThreadContext context){
if (stateName == Status.RUNNING){
System.out.println("线程设置结束:");
context.setState(new DeadState(Status.DEAD));
}
else System.out.println("线程不是运行状态,无法设置为结束状态");
}
public void suspend(ThreadContext context){
if (stateName == Status.RUNNING){
System.out.println("线程设置阻塞:");
context.setState(new BlockedState(Status.BLOCKED));
}
else System.out.println("线程不是运行状态,无法设置为阻塞状态");
}
}
public class StatePattern {
public static void main(String[] args) {
ThreadState state = new NewState(Status.NEW);
ThreadContext context = new ThreadContext();
context.setState(state);
context.start();
System.out.println(context.getState());
context.getCpu();
context.setState(new DeadState(Status.DEAD));
System.out.println(context.getState());
}
}
public enum Status {
NEW,
RUNNABLE,
RUNNING,
BLOCKED,
DEAD
}
public class ThreadContext {
private ThreadState state;
public Status getState() {
return state.stateName;
}
public void setState(ThreadState state) {
this.state = state;
}
public void start() {
if (state instanceof NewState s)
s.start(this);
else System.out.println("不是新建状态,无法启动");
}
public void getCpu(){
if (state instanceof RunnableState s)
s .getCpu(this);
else System.out.println("不是就绪状态,无法获取cpu");
}
public void suspend(){
if (state instanceof RunningState s)
s.suspend(this);
else System.out.println("不是运行状态,无法设置阻塞");
}
public void stop(){
if (state instanceof RunningState s)
s.stop(this);
else System.out.println("不是运行状态,无法设置结束");
}
public void resume() {
if (state instanceof BlockedState s)
s.resume(this);
else System.out.println("不是阻塞状态,无法设置就绪");
}
}
public abstract class ThreadState {
protected Status stateName;
}