概念
状态模式
(State Pattern)是一种行为型设计模式,用于解决对象在不同状态下的行为问题。它允许一个对象在其内部状态改变时改变它的行为。状态模式主要包含三个部分:上下文
(Context)、状态接口
(State)和具体状态实现类
(ConcreteState)。
组成角色
- 状态接口(State):定义一个接口,用于封装与上下文类的一个特定状态相关的行为。
- 具体状态实现类(ConcreteState):实现状态接口,定义与该状态相关的行为。
- 上下文(Context):维护一个 State 类型的对象实例,该实例定义当前的状态。
相关图示
图片来自:https://refactoringguru.cn/design-patterns/state
代码示例
//状态接口
interface State {
void handle(Context context);
}
//具体状态实现类ConcreteStateA、ConcreteStateB
class ConcreteStateA implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态是 A.");
//设置下一个执行状态节点
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB implements State {
@Override
public void handle(Context context) {
System.out.println("当前状态是 B.");
//设置下一个执行状态节点
context.setState(new ConcreteStateA());
}
}
//上下文对象
class Context {
//当前执行节点
private State state;
public Context(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
//执行节点逻辑
public void request() {
state.handle(this);
}
}
public class StatePatternDemo {
public static void main(String[] args) {
State initialState = new ConcreteStateA();
Context context = new Context(initialState);
//状态节点流转 A -> B -> A
context.request(); // 输出:当前状态是 A.
context.request(); // 输出:当前状态是 B.
context.request(); // 输出:当前状态是 A.
}
}
框架中的应用
一个常见的使用状态设计模式的例子是Java线程的状态管理。Java的Thread类使用了状态模式来表示线程的不同状态,例如:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED。这些状态之间的转换由Thread类和相关的方法控制。
Thread.State枚举,它定义了Java线程的各种状态:
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
线程状态之间的转换:
- NEW:当线程刚创建时,它处于NEW状态。在这个状态下,线程还没有开始执行。
- RUNNABLE:当调用线程的start()方法后,线程进入RUNNABLE状态。此时,线程已经开始执行或者准备执行,等待操作系统分配资源。
- BLOCKED:当线程试图获取一个已被其他线程锁定的对象的监视器(即进入synchronized块)时,线程进入BLOCKED状态。一旦锁被释放,线程将重新进入RUNNABLE状态。
- WAITING:当线程调用wait()、join()或LockSupport.park()方法时,线程进入WAITING状态。这表示线程正在等待另一个线程的通知或中断。当线程收到通知或中断时,它将重新进入RUNNABLE状态。
- TIMED_WAITING:当线程调用wait(long timeout)、sleep(long millis)、join(long millis)或LockSupport.parkNanos()等方法时,线程进入TIMED_WAITING状态。这表示线程正在等待另一个线程的通知、中断或超时。当线程收到通知、中断或超时时,它将重新进入RUNNABLE状态。
- TERMINATED:当线程执行完成或被中断时,它进入TERMINATED状态。在这个状态下,线程已经结束,不能再次启动。
状态切换图
适用场景
- 对象的行为随其状态改变而改变:当一个对象的行为因其内部状态而改变时,可以考虑使用状态模式。状态模式将对象的状态和行为分离,使得状态和行为可以独立地变化,提高了代码的灵活性和可维护性。
- 避免大量条件语句:状态模式可以减少因状态判断而导致的大量条件语句。通过使用状态模式,可以将状态相关的行为分散到各个状态类中,降低了代码的复杂性。
- 状态转换清晰:当一个对象的状态转换逻辑复杂且需要明确表示时,状态模式可以使状态转换更加清晰。状态模式将状态转换逻辑封装在状态类中,有助于理解和维护状态转换逻辑。
以下是一些使用状态设计模式的实际场景:
- 线程状态管理:Java线程状态管理是状态设计模式的一个典型应用。线程的状态(如新建、运行、阻塞等)由Thread.State枚举表示,状态之间的转换由Thread类及其相关方法控制。
- 工作流引擎:工作流引擎通常需要处理多个状态和状态之间的转换。状态模式可以帮助设计一个灵活的工作流引擎,使得状态和行为可以独立地变化。
- 游戏角色状态:在游戏开发中,角色可能有多种状态(如站立、行走、攻击等),并且状态之间可以相互转换。使用状态模式可以使游戏角色的状态管理更加清晰。
- 订单状态管理:在电商系统中,订单可能有多个状态(如待付款、待发货、已发货等),并且状态之间有一定的转换逻辑。状态模式可以帮助设计一个易于维护的订单状态管理系统。