You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

结合开闭原则优化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为例)

  1. 创建SemiLocked类实现State接口,处理自身输入逻辑并返回对应Trigger(比如INPUT_SECRET);
  2. 在Trigger枚举中添加新的触发类型(INPUT_SECRET);
  3. 在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));
    
  4. 无需修改已有的Locked和Unlocked类。

优化后的优势

  • 符合开闭原则:新增状态只需扩展代码,无需修改原有类;
  • 逻辑清晰:状态行为与转换规则分离,规则集中管理便于维护;
  • 性能优化:状态对象为单例,避免重复创建实例。

内容的提问来源于stack exchange,提问作者Zag Gol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 23:27:11