我一遍又一遍地问自己有什么好的代码,我读到了"接受最弱者,回归最强"的建议.
对我来说很明显为什么接受最弱的:该方法声明与其客户最弱的合同.因此,客户不需要"专门"对抗非常"强大"的界面.
"回归最强"对我来说并不是那么清楚.为什么我应该返回最强的接口?什么是最强大的界面?你如何量化强度?
假设有一个方法返回一系列元素.最弱的接口是IEnumerable类型.按照指南,我们应该像IList一样返回.但为什么?
我想问一个解释为什么要返回最强的界面.
我不认为返回"最强"(或者更确切地说,最具体或派生)类型是一个好主意,因为如果你的界面或合同指定你返回List<T>,如果你想Collection<T>在将来改变它,你将被卡住,因为这两者都是IList<T>没有共同祖先的不同实现.您必须修改界面.
你引用的口头禅似乎非常教条 - 总有例外,我只是说你应该坚持适合某项工作.这听起来像是网络/ IO编程原则的混蛋"在接受输入时要自由,但在输出的内容上要严格" - 但是与定义OO接口或实现的类型相比,网络/ IO编程是非常不同的与人类可读的规范(例如HTTP的RFC)相比,ABI是一种非常不同的野兽.
这个规则有几种形式,这是另一种形式:
这背后的原因是:
我们来举个例子吧.
假设您要创建一个方法,该方法接受整数集合,处理它们,然后返回一个新的整数集合.
一个非常好的实现可能是:
public IEnumerable<int> Process(IEnumerable<int> input) { ... }
Run Code Online (Sandbox Code Playgroud)
请注意,我不一定遵循这里的第二点,但这取决于方法的作用.如果该方法一次处理一个项目,则上述声明非常好,它表示您不一定要回到列表,数组或其他东西,只是"收集".
但是,我们假设该方法必须首先收集所有值,然后处理它们,然后返回它们.在这种情况下更好的声明可能是这样的:
public List<int> Process(IEnumerable<int> input) { ... }
Run Code Online (Sandbox Code Playgroud)
为什么这样更好?好吧,首先,通常情况下,调用者想要收集所有值,而现在他不必,它已经作为包含所有值的单个集合返回.此外,如果调用者只想继续使用这些值IEnumerable<int>,那也是可能的.
因此,规则的目的是增加灵活性,并在某些情况下提高性能(记忆或速度).
请注意,该规则并不意味着您应始终努力返回列表或数组或其他内容.您应该努力从已经构建的数据结构中返回"最具功能性"的类型.另请注意,您当然应该永远不会返回对内部数据结构的引用,这些引用将继续超出方法调用,而是返回一个副本.
有趣的概念 - 我以前从未明确听过的概念.这基本上是Postel定律 "你发送的内容是保守的,你收到的内容是自由的",这通常适用于跨系统通信.
IList是"更强大",因为它提供了更多的保证IEnumerable.一个IList支撑件的添加,删除,枚举等而IEnumerable只支持枚举.当然,List更强大,是一种具体类型.
至于建议本身的智慧 - 我认为在应用程序内部通常是一个好主意,对API设计者有一些严重的警告.
从积极的方面来说,返回"最强"类型允许调用者在不违反合同的情况下进行所有可能的操作(例如,通过铸造)或进行额外的工作(例如,将其复制IEnumerable到a中List).这通常是应用程序中的一个帮助,因为它在一个应用程序中,所以任何重大更改都将在编译时捕获并且可以轻松修复.
但是,对于需要关注向后兼容性的API(例如,由多个应用程序使用或独立部署),返回类型是合同的一部分.在这种情况下,你真的必须权衡永远支持IList回报而非弱者的重要性IEnumerable.那里的具体细节应该由API的意图决定,而不是遵守这条规则.
FWIW,我个人精辟的陈述将是"返回对调用者有用的东西,而不是更多." 我认为这是在单个应用程序的上下文中决定"对调用者有用的东西"的快捷方式,但在外部API中是有害的.
| 归档时间: |
|
| 查看次数: |
744 次 |
| 最近记录: |