密封类配合建造者模式的核心目标是让配置的可选状态显式化、不可扩展、编译期可穷举,从而在类型层面杜绝非法构造、遗漏分支或运行时类型错误。

用密封类(sealed class)配合建造者模式,核心目标是让配置的**可选状态显式化、不可扩展、编译期可穷举**,从而在类型层面杜绝非法构造、遗漏分支或运行时类型错误。这比普通 builder 更进一步——不只是“链式调用方便”,而是让“哪些配置合法”这件事由编译器强制保障。
用密封类建模配置的有限状态空间
把配置中所有可能的完成状态(如“未开始”“基础已设”“网络已配”“全部就绪”)定义为密封类的子类,每个子类代表 builder 当前所处的确定阶段。Kotlin 中 sealed class 天然禁止外部继承,且 when 表达式可被编译器检查是否穷举——这是安全性的根基。
例如:
- ConfigStage.Empty:初始态,只允许 setBase()
- ConfigStage.BaseSet:已设基础参数,允许 addNetwork() 或 setAuth()
- ConfigStage.Ready:所有必需项齐备,仅开放 build() 方法
每个阶段类可携带对应字段(如 BaseSet 持有 appName: String),避免用 nullable 字段或 Map 存储中间状态,消除空指针和键名拼写风险。
建造者方法返回精确的下一阶段类型
builder 的每个 setter 不再统一返回 this,而是返回**明确的下一阶段类型**。这样调用链天然具备类型引导性:IDE 能自动提示当前可调什么方法,编译器能拦截非法顺序(比如在 Empty 阶段直接调 addNetwork)。
实现上,每个方法声明为扩展函数或泛型成员函数,例如:
fun ConfigStage.Empty.setBase(name: String): ConfigStage.BaseSet-
fun ConfigStage.BaseSet.addNetwork(host: String): ConfigStage.BaseSet(同阶段复用) -
fun ConfigStage.BaseSet.build(): ConfigStage.Ready(终态)
这种签名设计让 builder 的调用路径变成一条受控的、类型驱动的状态迁移路径,而非任意跳转的“魔法链式调用”。
终态封装与不可变输出
最终的 ConfigStage.Ready 类应仅暴露只读属性,并提供 toConfig(): ImmutableConfig 方法。这个 ImmutableConfig 是真正的业务配置对象,所有字段 final / val,无 setter,构造即冻结。
关键点:
- Ready 类不提供任何修改方法,防止构建后意外篡改
- build() 方法只在 Ready 阶段存在,Empty 或 BaseSet 调用会编译报错
- 若需部分重置,必须新建 builder,而不是“回退”——状态机不支持逆向
配合 when + 密封类做配置校验与分支处理
由于所有阶段都是密封类子类,在需要根据配置完备程度做差异化处理的地方(如 UI 展示、条件初始化),可直接用 when 安全解构:
when (builderStage) {is ConfigStage.Empty -> showStartButton()is ConfigStage.BaseSet -> enableNetworkSection()is ConfigStage.Ready -> renderLaunchButton()-
}—— 编译器确保无遗漏,无需 else fallback
这种能力把“配置进度”从隐式逻辑(如一堆布尔标志位)提升为一等公民类型,大幅提升可维护性与协作清晰度。











