n3r*_*3rd 22 java collections abstraction
用Java编程我几乎总是出于习惯,写下这样的东西:
public List<String> foo() {
return new ArrayList<String>();
}
Run Code Online (Sandbox Code Playgroud)
大多数时候甚至没有考虑过它.现在,问题是:我是否应该始终将接口指定为返回类型?或者建议使用接口的实际实现,如果是,在什么情况下?
很明显,使用界面有很多优点(这就是它的原因).在大多数情况下,库函数使用的具体实现并不重要.但也许有些情况确实很重要.例如,如果我知道我将主要随机访问列表中的数据,LinkedList那就不好了.但是如果我的库函数只返回界面,我根本就不知道.为了安全起见,我甚至可能需要将列表明确地复制到ArrayList:
List bar = foo();
List myList = bar instanceof LinkedList ? new ArrayList(bar) : bar;
Run Code Online (Sandbox Code Playgroud)
但这看起来很可怕,我的同事可能会在自助餐厅里骂我.理所当然.
你们有什么感想?您的指导方针是什么?您何时倾向于抽象解决方案,何时会显示您的实施细节以获得潜在的性能提升?
duf*_*ymo 30
返回适当的接口以隐藏实现细节.您的客户应该只关心您的对象提供的内容,而不是您如何实现它.如果您从私有ArrayList开始,并稍后决定其他东西(例如,LinkedLisk,跳过列表等)更合适,您可以在不影响客户端的情况下更改实现,如果您返回接口.返回具体类型的那一刻,失去了机会.
例如,如果我知道我将主要随机访问列表中的数据,则LinkedList会很糟糕.但是如果我的库函数只返回界面,我根本就不知道.为了安全起见,我甚至可能需要将列表显式复制到ArrayList.
正如其他人提到的那样,您不必关心库如何实现功能,减少耦合并提高库的可维护性.
如果您作为库客户端可以证明实现对您的用例表现不佳,那么您可以联系负责人并讨论要遵循的最佳路径(针对此案例的新方法或仅更改实施) .
也就是说,你的例子充满了过早的优化.
如果该方法是或可能是关键的,它可能会提到文档中的实现细节.
小智 8
抱歉不同意,但我认为基本规则如下:
因此,在这种情况下,您希望将实现声明为:
public ArrayList<String> foo() {
return new ArrayList<String>();
}
Run Code Online (Sandbox Code Playgroud)
理由:输入法大家都已经知道并解释了:使用界面,句号。但是,输出案例可能看起来违反直觉。您希望返回实现,因为您希望客户端拥有有关接收内容的最多信息。在这种情况下,更多的知识就是更多的力量。
示例 1:客户端想要获取第 5 个元素:
list.get(4)示例 2:客户端要删除第 5 个元素:
list.remove()可选)。arrayList.remove(4)因此,使用接口很棒是一个重要的事实,因为它促进了可重用性,减少了耦合,提高了可维护性并使人们感到高兴……但仅当用作输入时。
所以,同样,规则可以表述为:
所以,下次,请返回执行。
如果没有能够用大量的CS引语来证明这一点(我自学成才),在设计课程时,我总是遵循"接受最少派生,回归最多"的口号,这让我很好这些年.
我想这意味着在接口与具体返回方面,如果你试图减少依赖关系和/或解耦,返回接口通常更有用.但是,如果具体的类实现更比一个接口上,它通常是你的方法的调用者更有用,以获得具体类背面(即"最派生"),而不是aribtrarily限制他们到一个返回对象的功能的子集- 除非你真的需要限制它们.然后,您还可以增加界面的覆盖范围.像这样的不必要的限制我比较无意义的类密封; 你永远都不会知道.只是谈谈该咒语的前一部分(对于其他读者),接受最少派生也为您的方法的调用者提供了最大的灵活性.
-Oisin
在OO编程中,我们希望尽可能地封装数据.尽可能隐藏实际的实现,尽可能地抽象出类型.
在这种情况下,我只会回答有意义的回报.将返回值作为具体类是否有意义?在你的例子中的Aka,问问自己:有人会在foo的返回值上使用特定于LinkedList的方法吗?
代码越抽象,更改后端时需要做的更改就越少.就这么简单.
另一方面,如果你最终将返回值转换为具体类,那么这是一个强烈的迹象,表明你应该返回具体的类.您的用户/团队成员不应该了解更多或更少的隐式合同:如果您需要使用具体方法,请返回具体类,以便清楚.
简而言之:代码抽象,但显式 :)
通常,对于面向公众的接口(例如API List),在具体实现(例如)上返回接口(例如ArrayList)会更好.
使用ArrayList或者LinkedList是库的实现细节,应该考虑该库的最常见用例.当然,在内部,如果提供的设施可以使处理更容易,那么使用private方法切换LinkedLists并不一定是坏事.
没有理由不在实现中使用具体的类,除非有充分的理由相信List稍后会使用其他类.但话说回来,只要面向公众的部分设计得很好,改变实施细节就不会那么痛苦.
图书馆本身应该是消费者的黑盒子,所以他们不必担心内部会发生什么.这也意味着应该对库进行设计,使其按照预期的方式使用.
API 方法是否返回接口或具体类并不重要;不管这里的每个人都怎么说,一旦编写了代码,您几乎永远不会更改实现类。
更重要的是:始终为您的方法参数使用最小范围的接口!这样,客户端就拥有最大的自由,并且可以使用您的代码甚至不知道的类。
当 API 方法返回时ArrayList,我对此完全没有疑虑,但是当它需要一个ArrayList(或全部为通用的Vector)参数时,我会考虑追捕程序员并伤害他,因为这意味着我不能使用Arrays.asList(),Collections.singletonList()或者Collections.EMPTY_LIST.
| 归档时间: |
|
| 查看次数: |
8402 次 |
| 最近记录: |