是否存在使用 Builder 模式创建的对象不可变的约定?

Is there a convention that objects created using the Builder pattern be immutable?

根据《设计模式:可重用面向对象软件的元素》一书,:

The Builder Pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.

通常,Builder 模式通过提供一种逐步构建对象的方法并提供一种实际 return 最终对象的方法来解决大量可选参数和不一致状态的问题.

使用构建器模式,我们将有一个生成对象的构建方法是不可变的。

我的问题:

我可以使用构建器模式在生成对象的 Class 中保留 setter 方法,从而允许改变构建的对象吗?

如果我去生产可变对象,我不应该使用构建器模式?

Builder Pattern 旨在替换所谓的伸缩构造函数(向@scottb 致敬)可选参数,而不是还有很多。它不要求 object 是不可变的。

此外,构建器通常 包含在 构建(a.k.a.build)时间 时重要的属性,因此名字 建造者。它不应包括在 object 的生命周期内发生变化但在构建后并不重要的属性。

从概念上讲,如果您有 Child 的生成器,唯一重要的三件事是 momdadchildGenes(boy/girl, 其他遗传 material). child 的身高或体重不应成为建造者的一部分,因为它部分受基因驱动,但会因出生时存在的因素(或"build"次)。

也就是说,除非你真的需要它,否则最好让 object 不可变。

希望对您有所帮助!

Builder Pattern 的价值不仅仅在于帮助解决伸缩参数问题。

  • 它们可以使 API 更易于客户使用,因为 setter 方法是自命名的,因此更容易记住。
  • Builder Pattern 启用可选参数,伸缩构造函数只能通过使用可能笨拙的重载来提供。
  • 使用构建器的客户端代码可以比使用构造函数的代码更自文档化,从而使客户端代码更容易(并且更便宜)维护
  • Builder Pattern 可以减少错误。使用伸缩构造函数可能会意外地转置大量相同类型的参数。在这种情况下,编译器不会报告错误,由此产生的错误可能会被远远移除并且难以追踪。
  • 可以在Builder 的构造函数签名中指定对象的强制参数。编译器会坚持这些强制参数总是在编译时提供。
  • 有用的 API 会随着时间的推移而演变;向构建器对象添加 setter 方法很容易,而管理一组重载的构造函数可能不那么容易且更容易出错。
  • 构建器模式是并发友好的。保持可变构建器对象线程受限相对简单,因此线程安全。

构建器对于构建不可变对象特别有用,因为对于此类对象,必须在构建时提供所有数据。当需要提供大量数据或者必须完成多个步骤时,构建器模式非常容易推荐。

没有规定构建器对象不能构建可变对象,但是对于可变对象,JavaBeans 模式以更少的代码提供了相同的好处(易读性、自我记录、减少错误倾向)。