4

在值对象上使用方法链接模式是否可以接受/良好做法(例如,返回一个新对象而不是这个)?是否有实施此解决方案的案例?

我想不出任何缺点,但我想听听你的观点。

4

3 回答 3

5

结论:这种做法是完全可以接受的。

我相信这通常是当你有一个不可变对象时发生的。不是改变原始对象,而是使用给定值创建一个新对象并返回。支持和反对使用方法链接执行此操作的论点与使用可变对象与不可变对象大致相同。

我唯一担心的是,这对类的调用者来说很清楚——它们不能依赖于与链接对象的身份相等性,并且必须明确调用不会改变原始对象。尽管如果他们实际上是在链接调用,他们就不会分配中间对象,因此不会有太大的风险。重要的是它们使用方法链中的最后一个对象。

以 java.lang.String 为例,String 的一个客户端这样做:

myString.trim().replace("a", "b").substring(3, 9);

... 没有任何意义,通常表示程序员的误解。他们应该做的是:

String myNewString = myString.trim().replace("a", "b").substring(3, 9);

...然后myNewString在后续操作中使用。有趣的是,Java 的静态分析工具 Findbugs 可以检测到这种误解的实例,并将其报告为可能的错误。

客户理解是主要情况。其他缺点包括如果值对象的创建成本非常高,那么在每条链上创建一个新对象将会对性能造成影响。您应该能够从您自己的场景中判断这是否可能是一个问题。在这种情况下,您可能希望实现构建器模式,而不是在每个方法链上创建一个新对象。

除此之外,我想不出任何其他问题。

于 2009-12-30T19:00:01.730 回答
2

许多java类提供不可变的值对象。java.lang.String、java.math.BigInteger 和 java.math.BigDecimal 是不可变值对象,它们的方法返回一个新对象。它最大的缺点是人们不了解它是不可变的,并认为他们正在改变原来的。

有些语言比其他语言更强调不变性。在 Ruby 中,字符串是可变的,并且集合通常提供一个返回副本的版本和另一个改变现有副本的版本(例如 Array#sort 和 Array#sort!)。在 Clojure 中,不变性是常态。

于 2009-12-30T18:55:35.390 回答
2

是的,这是一件非常好的事情。例子:

  • Java 和 .NET 中的字符串
  • DateTimeTimeSpan在 .NET中
  • Joda TimeNoda Time的多种类型
  • 函数式语言(如 F#)的列表

对于实现为不可变值对象的引用类型,缺点有时可能是您最终会生成大量垃圾。在任何一种情况下,您最终都会进行大量复制 - 不过这取决于具体情况。

于 2009-12-30T19:03:22.287 回答