返回具体或抽象数据类型?
我正在阅读《Code Complete》,在书的结尾,在有关重构的章节中,作者列出了在重构时提高代码质量应该做的一系列事情。
他的观点之一是始终返回尽可能特定类型的数据,特别是在返回集合、迭代器等时。因此,据我所知,而不是返回 Collection< ;String>
,如果您在方法内使用该数据类型,则应返回 HashSet
。
这让我很困惑,因为听起来他是在鼓励人们打破信息隐藏的规则。 现在,当谈论访问器时我明白了这一点,这是一个明确的案例。 但是,当计算和修改数据时,并且方法的抽象级别意味着没有直接的数据结构,我发现最好返回尽可能抽象的数据类型,只要数据不分崩离析(例如,我不会返回 Object
而不是 Iterable
)。
所以,我的问题是: Code Complete 的建议背后是否有更深层次的哲学,即始终返回尽可能具体的数据类型,并允许向下转型,而不是维持需要知道的基础,即我刚刚没看懂?
I'm in the middle of reading Code Complete, and towards the end of the book, in the chapter about refactoring, the author lists a bunch of things you should do to improve the quality of your code while refactoring.
One of his points was to always return as specific types of data as possible, especially when returning collections, iterators etc. So, as I've understood it, instead of returning, say, Collection<String>
, you should return HashSet<String>
, if you use that data type inside the method.
This confuses me, because it sounds like he's encouraging people to break the rule of information hiding. Now, I understand this when talking about accessors, that's a clear cut case. But, when calculating and mangling data, and the level of abstraction of the method implies no direct data structure, I find it best to return as abstract a datatype as possible, as long as the data doesn't fall apart (I wouldn't return Object
instead of Iterable<String>
, for example).
So, my question is: is there a deeper philosophy behind Code Complete's advice of always returning as specific a data type as possible, and allow downcasting, instead of maintaining a need-to-know-basis, that I've just not understood?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我认为在大多数情况下这是错误的。 它一定要是:
尽可能宽松,根据需要具体
在我看来,您应该始终返回 List 而不是 LinkedList 或 ArrayList,因为区别更多是实现细节而不是语义细节。 Google Collections api for Java 的人员更进一步:他们返回(并期望)迭代器就足够了。 但是,他们还建议尽可能返回 ImmutableList、-Set、-Map 等,以向调用者表明他不必制作防御性副本。
除此之外,我认为不同列表实现的性能并不是大多数应用程序的瓶颈。
I think it is simply wrong for the most cases. It has to be:
be as lenient as possible, be as specific as needed
In my opinion, you should always return List rather than LinkedList or ArrayList, because the difference is more an implementation detail and not a semantic one. The guys from the Google collections api for Java taking this one step further: they return (and expect) iterators where that's enough. But, they also recommend to return ImmutableList, -Set, -Map etc. where possible to show the caller he doesn't have to make a defensive copy.
Beside that, I think the performance of the different list implementations isn't the bottleneck for most applications.
大多数时候,我们应该返回一个接口,或者可能是一个表示返回值的抽象类型。 如果您返回 X 的列表,则使用 List。 如果需要返回列表类型,这最终会提供最大的灵活性。
也许后来您意识到您想要返回一个链接列表或只读列表等。如果您输入具体类型,您就会陷入困境,并且更改起来很痛苦。 使用接口可以解决这个问题。
@Gishu
如果你的 api 要求客户端在大多数情况下立即进行转换,那么你的设计就很糟糕。 如果客户需要转换到 Y,为什么还要返回 X。
Most of the time one should return an interface or perhaps an abstract type that represents the return value being returned. If you are returning a list of X, then use List. This ultimately provides maximum flexibility if the need arises to return the list type.
Maybe later you realise that you want to return a linked list or a readonly list etc. If you put a concrete type your stuck and its a pain to change. Using the interface solves this problem.
@Gishu
If your api requires that clients cast straight away most of the time your design is suckered. Why bother returning X if clients need to cast to Y.
找不到任何证据来证实我的主张,但想法/指南似乎是:
接受输入时尽可能宽松。 选择通用类型而不是专用类型。 这意味着客户可以将您的方法用于不同的专业类型。 因此,将 IEnumerable 或 IList 作为输入参数意味着该方法可以在 ArrayList 或 ListItemCollection 上运行。 它最大限度地提高了您的方法有用的机会。
返回值时尽可能严格。 如果可能的话,最好选择专门的类型。 这意味着客户端不必事后猜测或跳过障碍来处理返回值。 特殊类型也具有更强大的功能。 如果您选择返回 IList 或 IEnumerable,则调用者可以对您的返回值执行的操作数量大大减少 - 例如,如果您通过 ArrayList 返回 IList,要获取返回的元素数量 - 使用 Count 属性,客户必须垂头丧气。 但是这样的向下转型就违背了目的 - 今天有效......明天就不行了(如果您更改返回对象的类型)。 因此,出于所有目的,客户端无法轻松获取元素计数 - 导致他编写普通的样板代码(在多个位置或作为辅助方法)
这里的总结是它取决于上下文(大多数规则的例外)。 例如,如果返回值最可能的用途是客户端将使用返回的列表来搜索某些元素,则返回支持某种搜索方法的列表实现(类型)是有意义的。 让客户端尽可能方便地消费返回值。
Can't find any evidence to substantiate my claim but the idea/guideline seems to be:
Be as lenient as possible when accepting input. Choose a generalized type over a specialized type. This means clients can use your method with different specialized types. So an IEnumerable or an IList as an input parameter would mean that the method can run off an ArrayList or a ListItemCollection. It maximizes the chance that your method is useful.
Be as strict as possible when returning values. Prefer a specialized type if possible. This means clients do not have to second-guess or jump through hoops to process the return value. Also specialized types have greater functionality. If you choose to return an IList or an IEnumerable, the number of things the caller can do with your return value drastically reduces - e.g. If you return an IList over an ArrayList, to get the number of elements returned - use the Count property, the client must downcast. But then such downcasting defeats the purpose - works today.. won't tomorrow (if you change the Type of returned object). So for all purposes, the client can't get a count of elements easily - leading him to write mundane boilerplate code (in multiple places or as a helper method)
The summary here is it depends on the context (exceptions to most rules). E.g. if the most probable use of your return value is that clients would use the returned list to search for some element, it makes sense to return a List Implementation (type) that supports some kind of search method. Make it as easy as possible for the client to consume the return value.
我可以看到,在某些情况下,返回更具体的数据类型可能会很有用。 例如,知道返回值是 LinkedList 而不仅仅是 List 将允许您从列表中进行删除,因为知道这将是高效的。
I could see how, in some cases, having a more specific data type returned could be useful. For example knowing that the return value is a LinkedList rather than just List would allow you to do a delete from the list knowing that it will be efficient.
我认为,在设计接口时,应该设计一个方法来返回尽可能抽象的数据类型。 返回特定类型将使方法的目的更清楚地了解它们返回的内容。
另外,我会这样理解:
返回尽可能抽象的数据类型=返回尽可能具体的数据类型
,即当您的方法应该返回任何集合数据类型时返回集合而不是对象。
告诉我我是否错了。
I think, while designing interfaces, you should design a method to return the as abstract data type as possible. Returning specific type would make the purpose of the method more clear about what they return.
Also, I would understand it in this way:
Return as abstract a data type as possible = return as specific a data type as possible
i.e. when your method is supposed to return any collection data type return collection rather than object.
tell me if i m wrong.
特定的返回类型更有价值,因为它:
函数的返回类型是专门选择的,以满足其所有调用者的需求。 调用函数应该尽可能抽象地使用返回变量,因为调用函数知道如何使用数据。
是不是只需要遍历结构体就可以了? 是否需要对结构进行排序? 改造它? 克隆它? 这些问题只有调用者才能回答,因此可以使用抽象类型。 被调用的函数必须提供所有这些情况。
事实上,如果您现在最具体的用例是 Iterable< string > ,那就可以了。 但通常情况下 - 您的调用者最终将需要更多详细信息,因此从特定的返回类型开始 - 它不需要任何成本。
A specific return type is much more valuable because it:
The return type of a function is specifically chosen to cater to ALL of its callers. It is the calling function that should USE the return variable as abstractly as possible, since the calling function knows how the data will be used.
Is it only necessary to traverse the structure? is it necessary to sort the structure? transform it? clone it? These are questions only the caller can answer, and thus can use an abstracted type. The called function MUST provide for all of these cases.
If,in fact, the most specific use case you have right now is Iterable< string >, then that's fine. But more often than not - your callers will eventually need to have more details, so start with a specific return type - it doesn't cost anything.