结合开闭原则优化Java状态模式?减少新增状态改动方案问询
优化状态模式实现,减少新增状态的改动
你的实现核心问题是:状态转换逻辑硬编码在具体状态类(Locked/Unlocked)中,新增状态时必须修改已有类的代码,违反了开闭原则(对扩展开放,对修改关闭)。下面是针对性的优化方案:
核心思路
将状态行为处理与状态转换逻辑分离:让具体状态类仅负责当前状态下的输入行为,把状态转换规则集中到上下文(SecretKeeper)中管理,新增状态时只需扩展规则,无需修改原有代码。
1. 定义触发状态转换的事件枚举
用枚举统一管理所有触发转换的条件,避免硬编码判断:
enum Trigger { CORRECT_PASSWORD, // 输入正确密码 INPUT_ZERO, // 输入0触发锁定 // 新增状态时,仅需在这里添加新的触发条件 }
2. 重构State接口,分离行为与转换
修改State接口,让状态类仅处理输入行为,并返回触发的转换事件(无转换则返回null):
public interface State { Trigger handleInput(SecretKeeper sk, int digit); }
3. 迁移状态内部数据到上下文
原Locked类中的code是用户输入的密码片段,属于上下文的临时状态,而非状态对象本身。将其移到SecretKeeper中,让状态对象可以复用(单例模式):
import java.util.HashMap; import java.util.Map; public class SecretKeeper { private int secretCode; String secret1, secret2; private State state = Locked.INSTANCE; // 使用单例状态 private int inputCode = 0; // 原Locked类的code移至此处 public SecretKeeper(int secretCode, String secret1, String secret2) { this.secretCode = secretCode; this.secret1 = secret1; this.secret2 = secret2; initTransitions(); } // 封装输入密码的操作,避免状态类直接操作上下文数据 public void resetInputCode() { inputCode = 0; } public void appendDigitToInputCode(int digit) { inputCode = inputCode * 10 + digit; } public boolean isInputCodeCorrect() { return inputCode == secretCode; } void printSecret1() { System.out.println(secret1); } void printSecret2() { System.out.println(secret2); } // 集中管理状态转换规则 private Map<State, Map<Trigger, State>> transitionMap = new HashMap<>(); private void initTransitions() { // 配置Locked -> Unlocked的转换规则 transitionMap.put(Locked.INSTANCE, Map.of(Trigger.CORRECT_PASSWORD, Unlocked.INSTANCE)); // 配置Unlocked -> Locked的转换规则 transitionMap.put(Unlocked.INSTANCE, Map.of(Trigger.INPUT_ZERO, Locked.INSTANCE)); } // 处理输入的核心方法:先调用状态处理行为,再根据触发事件完成转换 void evKey(int digit) { Trigger trigger = state.handleInput(this, digit); if (trigger != null) { State nextState = transitionMap.get(state).get(trigger); if (nextState != null) { setState(nextState); } } } public void setState(State state) { this.state = state; } }
4. 重构具体状态类为单例
状态对象不再持有内部数据,可改为单例,避免重复创建实例:
// Locked状态类:仅处理输入逻辑,返回触发事件 public class Locked implements State { public static final Locked INSTANCE = new Locked(); private Locked() {} // 私有构造,保证单例 @Override public Trigger handleInput(SecretKeeper sk, int digit) { if (digit == 0) { sk.resetInputCode(); return null; // 无状态转换 } else { sk.appendDigitToInputCode(digit); if (sk.isInputCodeCorrect()) { sk.resetInputCode(); return Trigger.CORRECT_PASSWORD; // 触发转换到Unlocked } return null; } } } // Unlocked状态类:处理输入逻辑,返回触发事件 public class Unlocked implements State { public static final Unlocked INSTANCE = new Unlocked(); private Unlocked() {} @Override public Trigger handleInput(SecretKeeper sk, int digit) { if (digit == 0) { return Trigger.INPUT_ZERO; // 触发转换到Locked } else if (digit == 1) { sk.printSecret1(); } else if (digit == 2) { sk.printSecret2(); } return null; } }
新增状态的流程(以SemiLocked为例)
- 创建
SemiLocked类实现State接口,处理自身输入逻辑并返回对应Trigger(比如INPUT_SECRET); - 在
Trigger枚举中添加新的触发类型(INPUT_SECRET); - 在
SecretKeeper的initTransitions方法中添加新的转换规则:// 配置Locked -> SemiLocked、SemiLocked -> Unlocked的规则 transitionMap.put(Locked.INSTANCE, Map.of(Trigger.CORRECT_PASSWORD, SemiLocked.INSTANCE)); transitionMap.put(SemiLocked.INSTANCE, Map.of(Trigger.INPUT_SECRET, Unlocked.INSTANCE)); - 无需修改已有的
Locked和Unlocked类。
优化后的优势
- 符合开闭原则:新增状态只需扩展代码,无需修改原有类;
- 逻辑清晰:状态行为与转换规则分离,规则集中管理便于维护;
- 性能优化:状态对象为单例,避免重复创建实例。
内容的提问来源于stack exchange,提问作者Zag Gol
相关产品推荐
相关产品推荐

