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

问题描述 投票:0回答:2

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

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

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

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

我的问题:

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

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

java design-patterns constructor immutability builder
2个回答
11
投票

构建器模式旨在取代所谓的伸缩构造函数(向@scottb致敬)的可选参数,仅此而已。它不要求对象是不可变的。

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

从概念上讲,如果您有

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

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

希望有帮助!


8
投票

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

  • 它们可以使 API 更容易被客户端使用,因为 setter 方法是自命名的,因此更容易记住。
  • 构建器模式支持可选参数,伸缩构造函数只能通过使用潜在的尴尬重载来提供这些参数。
  • 使用构建器的客户端代码比使用构造函数的代码更具自文档性,从而使客户端代码更容易(且更便宜)维护
  • 建造者模式可以减少错误。 大量相同类型参数的列表可能会被伸缩构造函数意外地调换。 在这种情况下,编译器不会报告错误,并且产生的错误可能会被远远消除并且难以追踪。
  • 可以在 Builder 的构造函数签名中指定对象的强制参数。 编译器将坚持要求这些强制参数始终在编译时提供。
  • 有用的 API 随着时间的推移而发展;向构建器对象添加 setter 方法很容易,但管理一组重载的构造函数可能不太容易且更容易出错。
  • 构建器模式是并发友好的。 限制可变构建器对象线程相对简单,因此是线程安全的。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.