【问题标题】:Is there a convention that objects created using the Builder pattern be immutable?有没有约定使用 Builder 模式创建的对象是不可变的?
【发布时间】:2015-10-02 13:44:08
【问题描述】:

根据《Design Patterns: Elements of Reusable Object-Oriented Software》一书,:

构建器模式将复杂对象的构造与其表示分离,以便相同的构造过程可以创建不同的表示。

一般来说,构建器模式通过提供一种逐步构建对象的方法并提供一种实际返回最终对象的方法来解决大量可选参数和状态不一致的问题。

通过构建器模式,我们可以使用构建方法来生成不可变的对象。

我的问题:

我可以使用构建器模式在生成对象的类中保留设置方法,从而允许对构建的对象进行变异吗?

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

【问题讨论】:

  • 您要解决的实际问题是什么?您是在问a raptor will eat you 是否编写了一个构建可变对象的 Builder,还是有其他原因让您担心?
  • @DanielPryden 在工作中我发现了这个模式的实现,但是它允许修改构建的对象,所以如果这个动作打破了这个模式的建议之一,我就会自我介绍,即构建一个不可变对象。
  • 当然。构建的对象甚至可以具有可链接的设置器,因此您可以这样做obj.setA(..).setB(..) ...构建器本身就是这样的可变对象。

标签: java design-patterns constructor immutability builder


【解决方案1】:

Builder 模式旨在替换 可伸缩构造函数(向@scottb 致敬)用于可选参数,仅此而已。它不要求对象是不可变的。

此外,构建器通常应该仅包含在构造(也称为构建)时间重要的属性,因此名称为 builder。它不应该包括在对象生命周期内发生变化但在构造后并不重要的属性。

从概念上讲,如果您有Child 的构建器,那么唯一重要的三件事是mom、dad 和childGenes(男孩/女孩,其他遗传物质)。 孩子的身高或体重不应成为建造者的一部分,因为它部分由基因驱动,但会因出生时(或“建造”时间)之外的因素而不断变化。

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

希望有帮助!

【讨论】:

    【解决方案2】:

    建造者模式的价值不仅仅是帮助解决伸缩参数问题。

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多