2009-05-25 92 views
4

我正在阅读Code Complete,在本书的最后,在关于重构的章节中,作者列出了一些你应该做的事情,以便在重构时提高代码的质量。返回具体或抽象数据类型?

其中一个观点是返回集合,迭代器等,所以当人们总是返回的特定类型的数据尽可能,尤其是,正如我的理解,而不是返回,说,Collection<String>,你应该返回HashSet<String>,如果您在该方法内使用该数据类型。

这让我感到困惑,因为这听起来像是在鼓励人们打破信息隐藏规则。现在,我在谈论访问器时明白这一点,这是一个明确的案例。但是,当计算和修改数据时,并且该方法的抽象级别意味着没有直接的数据结构,我发现尽可能抽象的数据类型返回,只要数据不会分开(我wouldn例如,返回Object而不是Iterable<String>)。

所以,我的问题是: Code Complete的建议总是有一个更深的理念,即始终以特定的数据类型返回,并允许向下转换,而不是维持需要知道的基础,即I只是不明白?

回答

0

我可以看到在某些情况下,如何返回更具体的数据类型可能会有用。例如,如果知道返回值是一个LinkedList而不是List,将允许您从列表中进行删除,因为它知道这将是有效的。

+1

是的,在某些情况下,返回LinkedList有一个很好的理由。但是,一旦出现特定需求,经过充分的考虑,而不是默认情况下,我会改变返回类型。 – 2009-05-25 07:07:42

+0

那是错误的做法,你应该总是返回列表。如果你知道客户端会从你的列表中删除很多,那么返回LinkedList是明智的。 返回一个具体的类型而不是一个接口是大多数时候从来都不是正确的做法。方法是关于合同的,合同说我要返回一个X的列表。该列表如何做它的事情并不重要。 – 2009-05-25 07:21:12

+0

是的,但是如果(例如)客户必须迭代列表呢?通过使签名(因此文档)使用LinkedList作为返回类型,客户端知道他们不应该将列表视为随机访问列表。因此,即使所有列表都有List.get(int index),他们也知道要避免在返回的列表中使用该方法。基本上,当调用者有合理需要知道时,指定的返回类型应提供信息。 – 2009-05-25 08:15:13

1

无法找到任何证据来证明我的要求,但这个想法/准则似乎是:

接受输入时要尽可能宽松。选择一种特殊类型的泛化类型。这意味着客户可以将您的方法用于不同的专业类型。因此,IEnumerable或IList作为输入参数意味着该方法可以运行ArrayList或ListItemCollection。它最大限度地提高了您的方法的实用性。

返回值时尽可能严格。如果可能的话,优先考虑专门的类型这意味着客户不必再次猜测或跳过箍环来处理返回值。也有专门的类型有更多的功能。如果您选择返回一个IList或一个IEnumerable,则调用者可以对您的返回值进行大量处理,例如:如果您通过ArrayList返回IList,要获取返回的元素数量 - 使用Count属性,则客户端必须向下转发。但是,这种向下转换击败了目的 - 今天的作品......明天不会(如果你改变了返回对象的类型)。因此,对于所有目的,客户无法轻松获取元素数 - 导致他编写普通的样板代码(在多个位置或作为辅助方法)

此处的摘要取决于上下文大多数规则)。例如。如果最有可能使用您的返回值是客户端将使用返回的列表来搜索某个元素,那么返回支持某种搜索方法的List实现(类型)是有意义的。尽可能让客户端消耗返回值。

0

我认为,在设计接口时,您应该设计一种方法来尽可能地返回尽可能抽象的数据类型。返回特定类型会使方法的目的更加清楚它们返回的内容。

另外,我想知道它是这样的:

回归为抽象数据类型尽可能=返回的特定数据类型尽可能

即当你的方法应该返回任何收集数据键入返回集合而不是对象。

告诉我,如果我错了。

0

具体的返回类型是更有价值,因为它:

  1. 减少与铸造或反射
  2. 增加代码的可读性发现功能可能性能问题
  3. 不事实上,暴露一个以上是必要。

函数的返回类型是专门为迎合其所有调用者而选择的。调用函数应该尽可能抽象地使用返回变量,因为调用函数知道如何使用数据。

是否只需要遍历结构?是否有必要对结构进行分类?改造它?克隆它?这些只是呼叫者可以回答的问题,因此可以使用抽象类型。被调用函数必须提供所有这些情况。

如果实际上你现在最具体的用例是可重用的< string>,那很好。但更多的时候 - 你的呼叫者最终需要更多的细节,所以从一个特定的返回类型开始 - 它不需要任何费用。

1

大多数情况下,应该返回一个表示返回值的接口或抽象类型。如果您要返回X的列表,请使用List。如果需要返回列表类型,这最终会提供最大的灵活性。

也许以后你会意识到你想要返回一个链表或一个只读列表等等。如果你把一个具体的类型卡住了,那么它是一个改变的痛苦。使用界面解决了这个问题。

@Gishu

如果您的API要求客户投马上你的设计是愚弄大部分时间。如果客户需要投入Y,为什么还要返回X.

3

我认为这对大多数情况来说是错误的。它必须是: 尽可能宽松,越具体需要

在我看来,你应该总是返回列表,而不是LinkedList的或ArrayList的,因为不同的是更多的实现细节,而不是语义一。 Google collections api for Java这些人更进一步:他们返回(并期望)迭代器,这足够了。但是,他们也建议在可能的情况下返回ImmutableList,-Set,-Map等以显示主叫方,他不必做出防御性副本。

除此之外,我认为不同列表实现的性能不是大多数应用程序的瓶颈。