Spring AI 源码看不习惯之 Spec 设计模式
最近在阅读 Spring AI 源码时,发现其 API 极大量地使用了以 Spec 结尾的接口设计。看得很不习惯,还以为是什么java 新特性或者语法糖(放心,其实不是,咱java 8 还能再用100 年!);所以写一篇文章记录一下
1. 什么是 Spec 写法?
Spec 是 Specification(规范/说明书)的缩写。它通过“内部嵌套接口”和“流式返回值”,将一个复杂对象的配置拆解为多个专职的配置节点。
示例代码(不是什么新特性):
Java
public interface AIClient {
// 节点 1:专职负责用户提示词
interface UserSpec {
UserSpec text(String text);
UserSpec variable(String key, Object value);
// 配置完用户,可以点回主入口或直接执行
AIClient execute();
}
// 节点 2:专职负责系统预设
interface SystemSpec {
SystemSpec text(String text);
SystemSpec systemProperty(String key, String value);
}
// 节点 3:模型参数设置(如温度、TopP)
interface ConfigSpec {
ConfigSpec temperature(Double temp);
ConfigSpec maxTokens(Integer tokens);
}
// 入口方法:根据需求进入不同的配置“房间”
UserSpec user();
SystemSpec system();
ConfigSpec config();
}
// 链式调用:逻辑非常清晰,像是在不同的柜台办业务
aiClient.user()
.text("Hello, {name}")
.variable("name", "小庄")
.system()
.text("你是一个 SQL 专家")
.config()
.temperature(0.7)
.user() // 甚至可以再点回来
.execute();
2. 与传统 Builder 模式的异同
虽然两者都追求“流式调用(Fluent API)”,但在设计哲学上有所不同:
相同点
- 消除 Setter:避免了繁琐的
setXXX调用,让配置过程一气呵成。 - 方法链:核心逻辑都是通过方法返回对象实例(或其接口)来实现连续调用。
不同点
-
粒度控制:
Builder通常是一个平铺的结构,所有配置项都在一层;而Spec是树状结构。 -
引导性(关键区别) :
- Builder:输入
.之后,所有配置项(如:用户信息、系统参数、模型参数)会全部弹出,干扰项多。 - Spec:利用编译器实现强制引导。只有当你进入
.prompt()节点,才会看到用户相关的配置;这种“按需展现”极大降低了配置错误的可能性。
- Builder:输入
-
设计内聚:
Spec往往作为内部接口存在,能够更好地隐藏实现细节,让 API 看起来更像是一门领域专用语言(DSL)。
总结: 习惯了 Setter 的人看 Spec 会觉得绕,但这并不是什么java 新特性;简单说就是一个树状结构 builder(咱就不扯什么高深的设计结构了);spring-ai 的源码里基本都是这种写法;