【问题标题】:A method declaring a mutable data structure as an output and returning an immutable one actually一种将可变数据结构声明为输出并实际返回不可变数据结构的方法
【发布时间】:2014-10-14 21:25:07
【问题描述】:

最近,我正在就这个问题进行激烈的讨论。

假设我在 Java 中创建了这个方法:

 public Set<String> getRich() {
    return ImmutableSet<String> ....;
 }

每当我在拉取请求中看到这一点时,我都会大喊大叫并试图解释为什么它是错误的。通过这样做,我误导了我的方法的消费者,因为他们会得到一个 Set 的承诺。这意味着他们可以删除或添加元素。 javac 会很高兴地编译它,但会抛出 RuntimeException。此外,它违反了“Liskov 替换原则”

就个人而言,我总是这样做:

public ImmutableSet<String> getRich() {
    return ImmutableSet<String> ....;
}

这样,没有人会朝自己的脚开枪。

一种建议的方法是返回 Iterable。我认为这很糟糕,因为该方法的使用者将失去 HashSet、HashMap 或其他任何东西的潜在功能(无法调用 set.get(hash) )。

另一种方法是 - 作为消费者 - 创建 getRich() 方法的输出的副本。但是你如何确定消费者会这样做呢?

当然,有些人会坚持 OOP 设计原则并说:“始终针对接口编程”。对我来说——在这种特殊情况下——这是有史以来最糟糕的选择。

你会如何处理这个案子?

(题外话:这个案例是一个完美的例子,静态类型如何确保正确性,但永远无法确保正确性)。

【问题讨论】:

  • 问题从 ImmutableSet 实现 Set 的地方开始,即使实现没有...

标签: java oop inheritance design-patterns immutability


【解决方案1】:

技术上,将返回类型声明为 Set&lt;T&gt; 并不违反 LSP。

Set&lt;T&gt;.Add 的文档明确指出,实现可能会抛出 UnsupportedOperationException。 这意味着检查集合是否可变是客户的责任。

现在,让ImmutableSet&lt;T&gt; 扩展Set&lt;T&gt; 是否是一个不错的选择,这是值得商榷的。 我个人认为这是一个非常糟糕的选择——客户端代码不应该被 try/catch 乱扔,以确定一个集合是否是可变的。此外,Set&lt;T&gt; 甚至没有提供isMutable() 方法让客户轻松执行检查!为不可变集合提供单独的接口将是一种更简洁的设计。

我个人会解决这个设计缺陷,并按照您的建议,将返回类型声明为ImmutableSet&lt;T&gt;

您问题的第二部分是您应该返回ImmutableSet&lt;T&gt; 还是Iterable&lt;T&gt;:这实际上取决于您认为客户对您的API 的期望。需要考虑的事项:

  • 您的实施可能会改变吗?您认为您是否需要更改业务逻辑并返回一些其他集合?如果是这样,请使用Iterable&lt;T&gt;
  • 您的客户是否明确期望ImmutableSet&lt;T&gt;?如果没有,请使用Iterable&lt;T&gt;
  • 否则,您可能需要遵守Robustness principle,它声明“输入类型是逆变的,输出类型是协变的”。换句话说,为您的参数类型选择最抽象的类型,并为您的返回类型选择最具体的类型。

【讨论】:

  • 不是类型错误;但它违反了 LSP。
  • @larsmans 不是真的。如果您针对基类Set&lt;T&gt; 进行编程,则必须在尝试添加任何项目之前检查该集合是否可变 - 文档对此很清楚。如果我给你一个HashSet&lt;T&gt;,你的代码就可以工作了。如果我随后将 HashSet&lt;T&gt; 替换为 ImmutableSet&lt;T&gt;,您的代码将仍然工作。 LSP 成立。这只是一个设计缺陷。
  • 啊!你是对的,+1(并删除了我的答案)。 Java 应该有一个ImmutableSet 作为Setlike Python does 的超级接口。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2012-01-20
  • 1970-01-01
  • 2021-07-01
  • 2018-11-29
  • 1970-01-01
相关资源
最近更新 更多