Spring AI 源码看不习惯之 Spec 设计模式

4 阅读2分钟

Spring AI 源码看不习惯之 Spec 设计模式

最近在阅读 Spring AI 源码时,发现其 API 极大量地使用了以 Spec 结尾的接口设计。看得很不习惯,还以为是什么java 新特性或者语法糖(放心,其实不是,咱java 8 还能再用100 年!);所以写一篇文章记录一下

1. 什么是 Spec 写法?

SpecSpecification(规范/说明书)的缩写。它通过“内部嵌套接口”和“流式返回值”,将一个复杂对象的配置拆解为多个专职的配置节点。

示例代码(不是什么新特性):

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() 节点,才会看到用户相关的配置;这种“按需展现”极大降低了配置错误的可能性。
  • 设计内聚Spec 往往作为内部接口存在,能够更好地隐藏实现细节,让 API 看起来更像是一门领域专用语言(DSL)。


总结: 习惯了 Setter 的人看 Spec 会觉得绕,但这并不是什么java 新特性;简单说就是一个树状结构 builder(咱就不扯什么高深的设计结构了);spring-ai 的源码里基本都是这种写法;