如何用状态模式实现开闭原则:可扩展的有限状态机设计

心靈之曲

心靈之曲

2026-06-30

731人浏览

原创

如何用状态模式实现开闭原则:可扩展的有限状态机设计

本文介绍一种符合开闭原则的状态模式实现方式,通过将状态转换逻辑从上下文类中剥离并封装到各状态子类内部,使新增状态时无需修改现有代码,仅需添加新状态类即可。

本文介绍一种符合开闭原则的状态模式实现方式,通过将状态转换逻辑从上下文类中剥离并封装到各状态子类内部,使新增状态时无需修改现有代码,仅需添加新状态类即可。

在传统的状态模式实现中,状态间的流转逻辑(如“输入密码后跳转到 Unlocked”)往往分散在各个 State 实现类的 evKey() 方法中,直接调用 sk.setState(new XxxState())。这种设计违反了开闭原则(Open-Closed Principle, OCP):每新增一个状态(如 SemiLockedState),不仅需定义新类,还必须修改所有可能跳转到它的已有状态类(例如 LockedState 中需将 new Unlocked() 改为 new SemiLockedState()),导致高耦合与频繁变更。

理想的解决方案是:让每个状态类自主决定“满足条件后应切换为何种状态”,并将状态切换行为从上下文(SecretKeeper)中解耦出来。核心思路是:

  • State 接口统一声明 getSwitchedState() 方法,由具体状态类自行返回下一个状态实例;
  • 上下文 SecretKeeper 不再持有状态创建逻辑,仅负责协调:收集输入 → 触发状态处理 → 检查条件 → 调用 getSwitchedState() 完成切换;
  • 状态内部专注自身数据维护(如 code 累积)、业务行为(doStuff())和转换策略(getSwitchedState()),彼此隔离。

以下是重构后的关键代码结构:

ActionScript3设计模式 中文WORD版
ActionScript3设计模式 中文WORD版

本文档主要讲述的是ActionScript3设计模式;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看

下载
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(); // 仅此处切换状态,逻辑完全委托给状态自身
        }
    }
}
public interface State {
    void setCode(int digit);
    int getCode();
    State getSwitchedState(); // ✅ 关键:状态自决跳转目标
    void doStuff();           // 当前状态下的业务动作(非转换逻辑)
}

以新增 SemiLockedState 为例,只需定义新类,无需改动 LockedState、UnlockedState 或 SecretKeeper

public class SemiLockedState 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() {
        // 可灵活配置:输入正确密码后进入 Unlocked,或继续 SemiLocked,甚至新增 FinalState
        return new UnlockedState();
    }

    @Override
    public void doStuff() {
        // 半锁定状态下可限制部分功能,如仅允许输入但不响应打印指令
    }
}

注意事项与最佳实践:

  • getSwitchedState() 应返回新状态实例(而非复用单例),确保状态对象无共享状态;若需复用,可通过工厂或依赖注入管理;
  • doStuff() 中避免调用 setState(),防止状态切换逻辑泄露;所有跳转必须经由 evKey() 统一入口;
  • 若状态间存在复杂条件(如“连续输错3次进入 BlockedState”),可将计数器等上下文数据通过 SecretKeeper 传入状态方法,或引入 Context 参数对象解耦;
  • 配合枚举或状态机配置表,可进一步支持运行时动态加载状态,适用于规则引擎场景。

这种设计真正实现了“对扩展开放,对修改关闭”:添加 SemiLockedState 仅需新增一个类并调整初始状态赋值,原有代码零修改,系统可维护性与可演进性显著提升。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

3889

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

2860

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

2899

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

638

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

602

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

727

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1317

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

18846

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

647

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
ThinkPHP6.x API接口--十天技能课堂
ThinkPHP6.x API接口--十天技能课堂

共14课时 | 1.4万人学习

第二十四期_PHP8编程
第二十四期_PHP8编程

共86课时 | 3.6万人学习

Laravel 8 课程精讲(台湾同胞版)
Laravel 8 课程精讲(台湾同胞版)

共22课时 | 2.8万人学习