
本文介绍一种遵循开闭原则的状态模式实现方式:通过将状态转换逻辑封装到每个状态类内部,使新增状态无需修改现有状态类,只需添加新状态实现类即可。
本文介绍一种遵循开闭原则的状态模式实现方式:通过将状态转换逻辑封装到每个状态类内部,使新增状态无需修改现有状态类,只需添加新状态实现类即可。
在传统状态模式实现中(如原始代码),状态间的转移逻辑往往分散在各 evKey 方法内,导致新增状态时需反复修改多个已有状态类——这直接违反了开闭原则(Open-Closed Principle, OCP):即“对扩展开放,对修改关闭”。要真正解耦、提升可维护性,关键在于将“何时切换”与“切换到哪个状态”这两项职责,从上下文(SecretKeeper)中剥离,交由具体状态类自主决策。
✅ 改进核心思路
- SecretKeeper 不再直接调用 setState(new XxxState()),而是委托当前状态完成「输入处理 → 验证 → 决策跳转」全流程;
- 每个 State 实现类负责:
- 维护自身内部状态(如输入累积的密码);
- 定义输入行为(setCode + doStuff);
- 自主决定验证通过后应切换至的新状态(getSwitchedState());
- SecretKeeper.evKey() 变为统一协调者:仅执行标准流程,不感知具体状态逻辑。
✅ 重构后的关键代码结构
public class SecretKeeper {
private final int secretCode;
private final String secret1, secret2;
private State state;
public SecretKeeper(int secretCode, String secret1, String secret2) {
this.secretCode = secretCode;
this.secret1 = secret1;
this.secret2 = secret2;
this.state = new LockedState(); // 初始状态
}
void printSecret1() { System.out.println(secret1); }
void printSecret2() { System.out.println(secret2); }
boolean checkCode(int code) { return code == secretCode; }
void evKey(int digit) {
state.setCode(digit); // 输入处理
state.doStuff(); // 执行当前状态行为(如打印、重置等)
if (checkCode(state.getCode())) {
state = state.getSwitchedState(); // ✅ 状态切换由当前状态决定
}
}
}
对应接口与状态实现:
public interface State {
void setCode(int digit);
int getCode();
State getSwitchedState(); // ? 核心:切换目标由状态自己返回
void doStuff();
}
public class LockedState implements State {
private int code = 0;
@Override
public void setCode(int digit) {
if (digit == 0) code = 0;
else code = code * 10 + digit;
}
@Override
public int getCode() { return code; }
@Override
public State getSwitchedState() {
return new SemiLockedState(); // ✅ 新增 SemiLocked?只改此处!
}
@Override
public void doStuff() {
// 当前无副作用,仅累积输入
}
}
public class SemiLockedState implements State {
@Override
public void setCode(int digit) { /* ... */ }
@Override
public int getCode() { return 0; }
@Override
public State getSwitchedState() {
return new UnlockedState(); // 可灵活配置后续状态
}
@Override
public void doStuff() {
// 如:播放提示音、点亮指示灯等
}
}
public class UnlockedState implements State {
private int lastDigit;
@Override
public void setCode(int digit) { this.lastDigit = digit; }
@Override
public int getCode() { return lastDigit; }
@Override
public State getSwitchedState() {
return new LockedState(); // 或返回其他状态(如 TimeoutState)
}
@Override
public void doStuff() {
switch (lastDigit) {
case 1 -> printSecret1();
case 2 -> printSecret2();
case 0 -> {} // 保持 unlocked?或触发锁定?由业务定
default -> {}
}
}
// 注意:printSecret1/2 需通过 SecretKeeper 实例访问 —— 建议注入或回调
// 实际中可将 SecretKeeper 作为参数传入 doStuff(),避免静态调用
}
⚠️ 注意事项与最佳实践
- 避免静态方法依赖:原示例中 SecretKeeper.printSecret1() 是静态调用,破坏了封装性。推荐改为在 doStuff(StateContext context) 中传入上下文对象,或使用策略回调。
- 状态不可变性(可选):若状态切换频繁且需线程安全,可让 getSwitchedState() 返回新实例,并确保 state 字段 final + volatile(配合同步)。
- 状态生命周期管理:复杂场景下可引入状态工厂(StateFactory.getState(String name))或枚举驱动,进一步解耦创建逻辑。
- 测试友好性:每个状态类可独立单元测试其 setCode、getCode 和 getSwitchedState 行为,无需启动整个系统。
✅ 总结
遵循开闭原则的状态模式,本质是将变化点封装为可插拔的组件。当需求要求新增 SemiLocked 状态时,你只需:
- 创建 SemiLockedState 类并实现 State 接口;
- 在 LockedState.getSwitchedState() 中返回它;
- (可选)调整其他状态的跳转逻辑(如 UnlockedState 是否允许回到 SemiLocked)。
全程无需修改任何已有状态类的 evKey 或分支逻辑,也无需触碰 SecretKeeper 的核心流程——这才是真正可演进、易维护的面向对象设计。











