关键在于递归泛型约束T extends Builder<T>,使父类方法返回实际子类类型;子类需显式指定自身类型,如UserBuilder extends Builder<UserBuilder>;setter返回T,build()集中校验并创建不可变对象。

要让 Builder 支持真正类型安全的链式调用,关键不是简单地每个方法返回 this,而是让父类方法返回**调用方实际使用的子类类型**。这靠的是递归泛型约束——即让泛型参数限定为“自身或其子类”。
核心结构:递归泛型边界定义
声明抽象基类时,用 T extends Builder<T> 约束类型参数:
-
Builder<T>表示这个类是泛型的,且类型参数T必须是Builder的子类型 - 所有 setter 方法统一返回
T,而非Builder<T>或void - 子类继承时必须显式传入自身类型,如
class UserBuilder extends Builder<UserBuilder>
子类实现需配合 self() 或直接返回 this
有两种主流写法,都确保编译器能推导出具体类型:
- 方式一(推荐):在基类中定义
protected abstract T self(),子类重写返回this;各方法调用self()而非强制转型(T)this - 方式二:基类方法直接写
return (T)this,子类继承后无需额外实现,但强转略显隐晦 - 无论哪种,目的都是避免返回原始泛型类型导致后续无法调用子类特有方法(比如
UserBuilder自带的build())
build() 是唯一出口,承担终态校验与对象创建
链式调用只是“收集配置”,真正的构建动作和合法性检查必须集中在 build() 中:
- 不要在
setName()或setAge()里做空值校验——否则链中途可能中断,错误堆栈难定位 - 所有字段应在
build()内一次性验证(如 name 非空、age 在合理范围),再统一构造不可变的 Product 对象 - Product 类建议私有构造 + 只读属性,防止绕过 Builder 直接 new 实例
避免常见陷阱
实战中容易踩坑的地方:
- 返回新实例(如
return new UserBuilder())会丢失已设字段,必须始终返回this - 若 Builder 内含可变集合(如
List<String> roles),addRole()应复用原 List,不能this.roles = new ArrayList<>() - 不需要 Director 层——除非多个构建流程共享条件分支逻辑;普通场景直接
new XxxBuilder().xxx().xxx().build() - 终结方法(如
push()、build())必须返回void或具体产物类型,不可再返回 Builder 类型

















