状态模式的经典实现里,最让人头疼的问题就是:新增一个状态,得把周围一堆状态类的代码翻个底朝天。本文要聊的方案,恰恰把这层转换逻辑塞回状态自己手里——你只管加新类,旧代码一动都不用动。 核心思路:状态自治,上下文只做调度 先亮出核心思路:把“状态要切换到哪儿”的决定权,完整交给每个状态类自身。这样,上
状态模式的经典实现里,最让人头疼的问题就是:新增一个状态,得把周围一堆状态类的代码翻个底朝天。本文要聊的方案,恰恰把这层转换逻辑塞回状态自己手里——你只管加新类,旧代码一动都不用动。
先亮出核心思路:把“状态要切换到哪儿”的决定权,完整交给每个状态类自身。这样,上下文(比如那个管理密码的SecretKeeper)就只需要做三件事——接收输入、让当前状态干活、问一句“该切换了没?切到谁?”至于具体切到哪个新状态,那是每个状态自己的私事。
传统写法里呢?状态间的跳转通常散落在各个State的evKey()方法里,直接硬编码sk.setState(new XxxState())。这等于把“谁可以跳到谁”写死在了每个状态内部,每次新增一个状态——比如半锁定态SemiLockedState——Locked和Unlocked里可能都要加个分支判断。高耦合、低扩展,改一处牵全身,这恰恰是开闭原则最不待见的样子。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
理想的解法其实很直白:把“什么时候切”和“切到哪儿”拆开,让状态自己说话。具体做三件事:
getSwitchedState()显式声明,而不是硬编码new XxxState()。这样未来配合工厂或策略动态生成也非常自然。下面是对应的重构代码骨架,不妨先看一眼SecretKeeper的简化版本:
public class SecretKeeper {
private int secretCode;
private 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(); // 由状态自身决定下一状态
}
}
}
关键在State接口和实现类:
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(); // 或返回 LockedState,完全由该状态控制
}
@Override
public void doStuff() {
System.out.println("Semi-locked: awaiting confirmation...");
}
}
这套设计带来的好处,值得掰扯几下:
getSwitchedState()可以返回工厂创建的实例、缓存单例,甚至基于条件返回不同状态,未来要支持配置化状态机也不难。当然,落地时也得留点神:
getSwitchedState()里别塞太多业务逻辑(比如数据库查询),保持轻量。如果外部依赖避不开,通过构造注入传进去。Map> ),配合字符串驱动实现配置化切换,维护成本会低很多。总结一句话:这种设计不只是解决了“改一个状态要动一堆类”的痛点,更重要的是给出了一个真正可演进、好维护的有限状态机架构。下次你写状态机,不妨试试让状态自己决定下一步去哪。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述