SpringAI的场景
ChatClient
ChatClient提供了create方法和Builder模式来创建对象。create方法就可以看作是一个静态工厂方法,适合快速创建一个能用的ChatClient,Builder模式则支持更加精细的管理。
ChatClient是一个接口,其具体实现如DefaultChatClient倒也可以直接new,只不过要传入的是一个DefaultChatClientRequestSpec类,相当复杂。
Advisor
在Advisor中,它们的构造函数大多是私有的,只能通过Builder来创建不同种类的Advisor。图例为ChatMemoryAdvisor


Builder 模式和直接new对象是创建对象的两种不同方式,它们在代码可读性、灵活性、扩展性等方面存在显著区别,具体如下:
构造参数的处理
-
直接
new:如果类的构造函数参数较多(尤其是存在可选参数时),直接new会导致参数列表冗长,且参数顺序容易混淆,可读性差。例如:// 直接new,参数多且顺序易出错 User user = new User("张三", 25, "北京", "13800138000", "zhangsan@xxx.com");若参数中有多个同类型值(如多个字符串),很容易传错顺序,且难以直观区分每个参数的含义。
-
Builder 模式 :通过链式调用设置参数,每个参数的含义清晰 ,支持可选参数灵活配置,无需传递无意义的默认值。例如:
// Builder模式,参数清晰,可选参数按需设置 User user = new User.Builder() .name("张三") .age(25) .address("北京") .build();即使参数很多,也能通过方法名明确每个参数的作用,避免混淆。
对象的不可变性
-
直接
new:若类提供setter方法,对象创建后状态仍可被修改,无法保证不可变性 ;若不提供setter,则必须在构造时传入所有参数(包括可选参数),灵活性差。 -
Builder 模式 :通常配合不可变类 设计:Builder 内部负责接收参数,最终通过
build()方法创建不可变对象(对象无setter,属性为final)。例如:public class User { private final String name; private final int age; private final String address; private User(Builder builder) { this.name = builder.name; this.age = builder.age; this.address = builder.address; } // 无setter,保证不可变 public static class Builder { private String name; private int age; private String address; public Builder name(String name) { this.name = name; return this; } // ...其他setter方法 public User build() { return new User(this); } } }这样创建的
User对象一旦生成,状态就无法修改,线程安全性更高。
复杂对象的构建逻辑
-
直接
new:仅能创建简单对象,若对象包含复杂的组件依赖或初始化逻辑(如对象 A 依赖对象 B 和 C,且 B、C 也需要复杂初始化),直接new会导致代码耦合严重,逻辑分散。 -
Builder 模式 :可将复杂对象的构建逻辑封装在 Builder 中,分离 "对象表示" 和 "构建过程"。例如创建一个包含多个组件的
Computer对象:Computer computer = new Computer.Builder() .cpu("Intel i9") .memory("32GB") .disk("1TB SSD") .gpu("RTX 4090") // 可选组件 .build();Builder 内部可处理组件的依赖关系(如必须有 CPU 和内存,GPU 可选),甚至在
build()中校验参数合法性(如内存大小不能为 0)。
扩展性
-
直接
new:若需要新增参数,必须修改构造函数,违反 "开闭原则",且所有调用new的地方都需调整,维护成本高。 -
Builder 模式 :新增参数时,只需在 Builder 中添加对应的设置方法,原有的
build()逻辑和调用代码无需修改,扩展性更好。例如新增phone参数:public static class Builder { // ...原有属性 private String phone; public Builder phone(String phone) { this.phone = phone; return this; } // build()无需修改 }调用方按需选择是否设置
phone,不影响旧代码。
使用场景
-
直接
new:适用于简单对象(参数少、无复杂逻辑),如:List<String> list = new ArrayList<>(); -
Builder 模式 :适用于复杂对象(参数多、有可选参数、需不可变性或复杂构建逻辑),如:
- 框架中的配置对象(如 OkHttp 的
OkHttpClient.Builder); - 数据库查询条件构建(如 MyBatis 的
SqlSessionFactoryBuilder); - 需保证不可变的领域对象(如订单、用户信息)。
- 框架中的配置对象(如 OkHttp 的
总结
| 特性 | 直接new |
Builder 模式 |
|---|---|---|
| 参数可读性 | 差(参数多易混淆) | 好(链式调用,参数名明确) |
| 对象不可变性 | 难保证(需无 setter + 全参构造) | 易保证(通过 Builder 构建不可变对象) |
| 复杂构建逻辑 | 难以封装 | 可封装在 Builder 中,逻辑清晰 |
| 扩展性 | 差(修改构造函数影响所有调用) | 好(新增参数不影响旧代码) |
| 适用场景 | 简单对象 | 复杂对象、不可变对象、多参数对象 |
Builder 模式通过封装构建过程 和链式调用 解决了直接new的痛点,但会增加少量代码量(需定义 Builder 类)。在实际开发中,应根据对象复杂度选择合适的创建方式。