我一次又一次地问自己什么是好的代码,我读到了“接受最弱的,返回最强的”的建议。
对我来说,接受最弱的原因是显而易见的:该方法声明了与其客户端之间可能存在的最弱的契约。因此,客户端不需要针对非常“强大”的接口进行“专门化”。
“回归最强者”对我来说不是很清楚。为什么我要尽可能返回最强的接口?最强的接口是什么?你如何量化其强度?
假设有一个返回元素序列的方法。最弱的接口将是IEnumerable类型。遵循这个指导原则,我们应该返回一些像IList这样的东西。但是为什么呢?
我想问一下为什么要返回最强的接口。
发布于 2013-06-05 16:24:12
这个规则有几种形式,下面是另一种形式:
这背后的原因是为了让它:
让我们举个例子。
假设您想要创建一个方法,该方法接受一个整数集合,处理它们,然后返回一个新的整数集合。
一个很好的实现方式可能是:
public IEnumerable<int> Process(IEnumerable<int> input) { ... }请注意,我不一定要遵循这里的第二点,但这取决于方法的作用。如果该方法一次处理一项,上面的声明就很好,它表明您不一定要返回一个列表、一个数组或诸如此类的东西,只是“一个集合”。
但是,让我们假设该方法必须首先收集所有的值,然后处理它们,然后返回它们。在这种情况下,更好的声明可能是:
public List<int> Process(IEnumerable<int> input) { ... }为什么这样更好?首先,很多时候,调用者想要收集所有的值,现在他不需要这样做了,它已经作为一个包含所有值的集合返回了。此外,如果调用者只想继续使用这些值作为IEnumerable<int>,也可以这样做。
因此,该规则的目的是提高灵活性,在某些情况下还可以提高性能(内存或速度)。
请注意,规则 not意味着您应该始终努力返回一个列表或数组或其他东西。相反,您应该努力从已经构建的数据结构中返回“最具功能性”的类型。还要注意,您当然不应该返回对内部数据结构的引用,这些内部数据结构将在方法调用之后继续存在,而应该返回一个副本。
发布于 2013-06-05 15:56:34
我不认为返回“最强的”(或者更确切地说,是最具体的或者派生的)类型一定是个好主意,因为如果您的接口或约定指定返回List<T>,那么如果您将来想要将其更改为Collection<T>,您将陷入困境,因为这两种类型都是不同的IList<T>实现,没有共同的祖先。你必须修改界面。
你引用的咒语似乎非常教条--总是有例外的,我只想说,你应该坚持对给定工作合适的做法。这听起来像是对网络/IO编程原则“接受输入的内容要宽松,输出的内容要严格”的私生化,但与定义OO接口或实现的类型相比,网络/IO编程是非常不同的,因为ABI与人类可读的规范(例如HTTP的RFC )相比是非常不同的。
发布于 2013-06-05 16:15:21
有趣的概念--一个我从未明确听说过的概念。它基本上是Postel's Law“发送的内容要保守,接收的内容要自由”,这通常应用于跨系统通信。
与IEnumerable相比,IList“更强大”,因为它提供了更多的保证。IList支持添加、删除、枚举等操作,而IEnumerable仅支持枚举。当然,List更强大,它是一个具体的类型。
至于这个建议本身的智慧--我认为这通常是一个在应用程序中的好主意,但对API设计者有一些严重的警告。
积极的一面是,返回“最强”类型允许调用者在不破坏约定(例如,通过强制转换)或执行额外工作(例如,将IEnumerable复制到List中)的情况下执行所有可能的操作。这通常是应用程序中的帮助,因为它在单个应用程序中,任何破坏性的更改都将在编译时被捕获,并且可以很容易地修复。
然而,对于需要关注向后兼容性的API(例如,被多个应用程序使用,或者独立部署),返回类型是契约的一部分。在这种情况下,你真的需要权衡永远支持IList返回而不是更弱的IEnumerable的重要性。这里的细节应该由API的意图决定,而不是遵循这个规则。
顺便说一句,我个人简洁的声明类似于“返回对调用者有用的东西,不要再多了”。我认为这是一条捷径,可以在单个应用程序的上下文中决定“什么对调用者有用”,但在外部API中却是有害的。
https://stackoverflow.com/questions/16934214
复制相似问题