基本概念
状态模式:是一种行为型设计模式,允许对象在内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
核心思想:将状态抽象为独立的类,上下文对象持有状态对象的引用,当状态改变时,只需更换状态对象,从而改变上下文的行为,避免使用大量条件判断语句。
核心结构
State
(状态接口):定义所有具体状态必须实现的接口,声明状态相关的方法
ConcreteState
(具体状态):实现状态接口,定义特定状态下的行为
Context
(上下文):持有当前状态对象的引用,将状态相关的请求委托给当前状态对象处理
示例说明
场景:设计一个手机播放器,具有”播放”、”暂停”、”停止”三种状态,不同状态下点击按钮会有不同行为。
- 状态接口
1 2 3 4 5 6 7
| public interface PlayerState { void clickPlay(); void clickPause(); void clickStop(); }
|
- 播放状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class PlayingState implements PlayerState { @Override public void clickPlay() { System.out.println("正在播放,点击播放无效"); }
@Override public void clickPause() { System.out.println("从播放状态切换到暂停状态"); PlayerContext.setState(new PausedState()); }
@Override public void clickStop() { System.out.println("从播放状态切换到停止状态"); PlayerContext.setState(new StoppedState()); } }
|
- 暂停状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class PausedState implements PlayerState { @Override public void clickPlay() { System.out.println("从暂停状态切换到播放状态"); PlayerContext.setState(new PlayingState()); }
@Override public void clickPause() { System.out.println("正在暂停,点击暂停无效"); }
@Override public void clickStop() { System.out.println("从暂停状态切换到停止状态"); PlayerContext.setState(new StoppedState()); } }
|
- 停止状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class StoppedState implements PlayerState { @Override public void clickPlay() { System.out.println("从停止状态切换到播放状态"); PlayerContext.setState(new PlayingState()); }
@Override public void clickPause() { System.out.println("未播放,点击暂停无效"); }
@Override public void clickStop() { System.out.println("已停止,点击停止无效"); } }
|
- 上下文类(播放器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class PlayerContext { private static PlayerState state;
public static void setState(PlayerState newState) { state = newState; }
public static void clickPlay() { state.clickPlay(); }
public static void clickPause() { state.clickPause(); }
public static void clickStop() { state.clickStop(); } }
|
- 验证测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Test { public static void main(String[] args) { PlayerContext.setState(new StoppedState()); System.out.println("===== 播放器状态测试 ====="); PlayerContext.clickPlay(); PlayerContext.clickPause(); PlayerContext.clickPlay(); PlayerContext.clickStop(); PlayerContext.clickPause(); } }
|
- 执行结果:
1 2 3 4 5 6 7 8 9
| ===== 播放器状态测试 ===== 从停止状态切换到播放状态 从播放状态切换到暂停状态 从暂停状态切换到播放状态 从播放状态切换到停止状态 未播放,点击暂停无效 总结
|
对象在内部状态改变时改变其行为:状态模式将状态封装进分离的类,并把行为委托当前状态的对象,行为随着内部状态而改变。
对象看起来好像改变了它的类:使用组合来简单引用不同的状态对象,造成类改变的假象。
类图如下:

总结
优点
- 封装状态逻辑:状态转换逻辑被封装在具体状态类中,代码更清晰;
- 符合开闭原则:新增状态只需添加新的状态类,无需修改原有代码;
- 状态解耦:状态之间相互独立,减少了条件判断语句(如if-else);
- 行为动态变化:上下文对象的行为随状态切换而动态改变;
缺点
- 类数量增加:每个状态需要独立的类,可能导致类数量过多;
- 状态转换复杂性:复杂状态转换逻辑可能需要在状态类或上下文中维护;
- 上下文与状态耦合:上下文需要知道所有具体状态类,存在一定耦合;
使用场景
- 状态机系统:如工作流引擎、游戏角色状态、电梯状态控制
- 界面状态管理:如按钮的启用/禁用状态、对话框的显示/隐藏状态
- 设备状态控制:如打印机的就绪/打印/错误状态
- 订单状态管理:如电商系统中订单的创建/支付/发货/完成状态
与其他模式的对比
与策略模式的区别:
- 策略模式的状态切换由客户端控制,状态模式的状态切换由状态内部逻辑控制;
- 策略模式关注算法的选择,状态模式关注状态的变化
与责任链模式的区别:
- 责任链模式处理请求的对象链是固定的,状态模式的状态切换是动态的;
- 责任链模式关注请求的传递,状态模式关注状态相关的行为变化;