when programming in Java I practically always, just out of habit, write something like this:
当我用Java编程时,我几乎总是出于习惯,写下这样的东西:
public List<String> foo() {
return new ArrayList<String>();
}
Most of the time without even thinking about it. Now, the question is: should I always specify the interface as the return type? Or is it advisable to use the actual implementation of the interface, and if so, under what circumstances?
大多数时候甚至没有考虑过它。现在,问题是:我是否应该始终将接口指定为返回类型?或者建议使用接口的实际实现,如果是,在什么情况下?
It is obvious that using the interface has a lot of advantages (that's why it's there). In most cases it doesn't really matter what concrete implementation is used by a library function. But maybe there are cases where it does matter. For instance, if I know that I will primarily access the data in the list randomly, a LinkedList
would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList
:
很明显,使用界面有很多优点(这就是它的原因)。在大多数情况下,库函数使用的具体实现并不重要。但也许有些情况确实很重要。例如,如果我知道我将主要访问列表中的数据,则LinkedList会很糟糕。但是如果我的库函数只返回界面,我根本就不知道。为了安全起见,我甚至可能需要将列表显式复制到ArrayList:
List bar = foo();
List myList = bar instanceof LinkedList ? new ArrayList(bar) : bar;
but that just seems horrible and my coworkers would probably lynch me in the cafeteria. And rightfully so.
但这似乎很可怕,我的同事可能会在自助餐厅里诽谤我。理所当然。
What do you guys think? What are your guidelines, when do you tend towards the abstract solution, and when do you reveal details of your implementation for potential performance gains?
你们有什么感想?您的指导方针是什么?您何时倾向于抽象解决方案,何时会显示您的实施细节以获得潜在的性能提升?
12 个解决方案
#1
For instance, if I know that I will primarily access the data in the list randomly, a LinkedList would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList.
例如,如果我知道我将主要访问列表中的数据,则LinkedList会很糟糕。但是如果我的库函数只返回界面,我根本就不知道。为了安全起见,我甚至可能需要将列表显式复制到ArrayList。
As everybody else has mentioned, you just mustn't care about how the library has implemented the functionality, to reduce coupling and increasing maintainability of the library.
正如其他人提到的那样,您不必关心库如何实现功能,减少耦合并提高库的可维护性。
If you, as a library client, can demonstrate that the implementation is performing badly for your use case, you can then contact the person in charge and discuss about the best path to follow (a new method for this case or just changing the implementation).
如果您作为库客户端可以证明实现对您的用例表现不佳,那么您可以联系负责人并讨论要遵循的最佳路径(针对此案例的新方法或仅更改实施) 。
That said, your example reeks of premature optimization.
也就是说,你的例子充满了过早的优化。
If the method is or can be critical, it might mention the implementation details in the documentation.
如果该方法是或可能是关键的,它可能会提到文档中的实现细节。
#2
Return the appropriate interface to hide implementation details. Your clients should only care about what your object offers, not how you implemented it. If you start with a private ArrayList, and decide later on that something else (e.g., LinkedLisk, skip list, etc.) is more appropriate you can change the implementation without affecting clients if you return the interface. The moment you return a concrete type the opportunity is lost.
返回适当的接口以隐藏实现细节。您的客户应该只关心您的对象提供的内容,而不是您如何实现它。如果您从私有ArrayList开始,并稍后决定其他东西(例如,LinkedLisk,跳过列表等)更合适,则可以在不返回接口的情况下更改实现而不影响客户端。返回具体类型的那一刻,机会就会消失。
#3
In OO programming, we want to encapsulate as much as possible the data. Hide as much as possible the actual implementation, abstracting the types as high as possible.
在OO编程中,我们希望尽可能地封装数据。尽可能隐藏实际的实现,尽可能地抽象出类型。
In this context, I would answer only return what is meaningful. Does it makes sense at all for the return value to be the concrete class? Aka in your example, ask yourself: will anyone use a LinkedList-specific method on the return value of foo?
在这种情况下,我只会回答有意义的回报。将返回值作为具体类是否有意义?在你的例子中,Aka问自己:有人会在foo的返回值上使用特定于LinkedList的方法吗?
- If no, just use the higher-level Interface. It's much more flexible, and allows you to change the backend
- If yes, ask yourself: can't I refactor my code to return the higher-level interface? :)
如果不是,只需使用更高级别的接口即可。它更加灵活,允许您更改后端
如果是,请问自己:我不能重构我的代码以返回更高级别的界面吗? :)
The more abstract is your code, the less changes your are required to do when changing a backend. It's as simple as that.
您的代码越抽象,更改后端时您需要做的更改就越少。就这么简单。
If, on the other hand, you end up casting the return values to the concrete class, well that's a strong sign that you should probably return instead the concrete class. Your users/teammates should not have to know about more or less implicit contracts: if you need to use the concrete methods, just return the concrete class, for clarity.
另一方面,如果你最终将返回值转换为具体类,那么这是一个强烈的迹象,表明你应该返回具体的类。您的用户/团队成员不应该了解更多或更少的隐式合同:如果您需要使用具体方法,只需返回具体类,以便清楚。
In a nutshell: code abstract, but explicitly :)
简而言之:代码摘要,但显式:)
#4
In general, for a public facing interface such as APIs, returning the interface (such as List
) over the concrete implementation (such as ArrayList
) would be better.
通常,对于面向公众的接口(例如API),在具体实现(例如ArrayList)上返回接口(例如List)会更好。
The use of a ArrayList
or LinkedList
is an implementation detail of the library that should be considered for the most common use case of that library. And of course, internally, having private
methods handing off LinkedList
s wouldn't necessarily be a bad thing, if it provides facilities that would make the processing easier.
使用ArrayList或LinkedList是库的实现细节,应该考虑该库的最常见用例。当然,在内部,让私人方法交出LinkedLists不一定是坏事,如果它提供的设施可以使处理更容易。
There is no reason that a concrete class shouldn't be used in the implementation, unless there is a good reason to believe that some other List
class would be used later on. But then again, changing the implementation details shouldn't be as painful as long as the public facing portion is well-designed.
没有理由不在实现中使用具体类,除非有充分的理由相信稍后将使用其他List类。但话说回来,只要面向公众的部分设计得很好,改变实施细节就不会那么痛苦。
The library itself should be a black box to its consumers, so they don't really have to worry about what's going on internally. That also means that the library should be designed so that it is designed to be used in the way it is intended.
图书馆本身应该是消费者的黑盒子,因此他们不必担心内部会发生什么。这也意味着应该对库进行设计,使其按照预期的方式使用。
#5
Without being able to justify it with reams of CS quotes (I'm self taught), I've always gone by the mantra of "Accept the least derived, return the most derived," when designing classes and it has stood me well over the years.
如果没有能够用大量的CS引用来证明它(我是自学成才的话),在设计课程时,我总是遵循“接受最少派生,回归最多派”的口号,这让我很好这些年。
I guess that means in terms of interface versus concrete return is that if you are trying to reduce dependencies and/or decouple, returning the interface is generally more useful. However, if the concrete class implements more than that interface, it is usually more useful to the callers of your method to get the concrete class back (i.e. the "most derived") rather than aribtrarily restrict them to a subset of that returned object's functionality - unless you actually need to restrict them. Then again, you could also just increase the coverage of the interface. Needless restrictions like this I compare to thoughtless sealing of classes; you never know. Just to talk a bit about the former part of that mantra (for other readers), accepting the least derived also gives maximum flexibility for callers of your method.
我想这意味着在接口与具体返回方面,如果你试图减少依赖关系和/或解耦,返回接口通常更有用。但是,如果具体类实现的不仅仅是那个接口,那么对于方法的调用者来说,通常更有用的是获取具体类(即“最派生”),而不是将它们无条件地限制为返回对象的功能的子集。 - 除非你真的需要限制它们。然后,您还可以增加界面的覆盖范围。像这样的不必要的限制我比较无意义的类密封;你永远都不会知道。只是谈谈该咒语的前一部分(对于其他读者),接受最少派生也为您的方法的调用者提供了最大的灵活性。
-Oisin
#6
As a rule, I only pass back internal implementations if I am in some private, inner workings of a library, and even so only sparingly. For everything that is public and likely to be called from the outside of my module I use interfaces, and also the Factory pattern.
作为一项规则,如果我在库的某些私有内部工作中,我只会传回内部实现,即使只是谨慎。对于所有公共的,可能从我的模块外部调用的东西,我使用接口,以及Factory模式。
Using interfaces in such a way has proven to be a very reliable way to write reusable code.
以这种方式使用接口已被证明是编写可重用代码的一种非常可靠的方法。
#7
The main question has been answered already and you should always use the interface. I however would just like to comment on
已经回答了主要问题,您应该始终使用界面。不过我想评论一下
It is obvious that using the interface has a lot of advantages (that's why it's there). In most cases it doesn't really matter what concrete implementation is used by a library function. But maybe there are cases where it does matter. For instance, if I know that I will primarily access the data in the list randomly, a LinkedList would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList.
很明显,使用界面有很多优点(这就是它的原因)。在大多数情况下,库函数使用的具体实现并不重要。但也许有些情况确实很重要。例如,如果我知道我将主要访问列表中的数据,则LinkedList会很糟糕。但是如果我的库函数只返回界面,我根本就不知道。为了安全起见,我甚至可能需要将列表显式复制到ArrayList。
If you are returning a data structure that you know has poor random access performance -- O(n) and typically a LOT of data -- there are other interfaces you should be specifying instead of List, like Iterable so that anyone using the library will be fully aware that only sequential access is available.
如果你要返回的数据结构你知道它的随机访问性能很差 - O(n)并且通常有很多数据 - 你应该指定其他接口而不是List,比如Iterable,这样任何使用该库的人都会充分意识到只有顺序访问可用。
Picking the right type to return isn't just about interface versus concrete implementation, it is also about selecting the right interface.
选择正确的类型返回不仅仅是关于接口与具体实现,还有关于选择正确的接口。
#8
It doesn't matter all that much whether an API method returns an interface or a concrete class; despite what everyone here says, you almost never change the implementiation class once the code is written.
API方法是返回接口还是具体类并不重要;尽管这里的每个人都说过,但一旦代码编写完成,你几乎从不改变实现类。
What's far more important: always use minimum-scope interfaces for your method parameters! That way, clients have maximal freedom and can use classes your code doesn't even know about.
更重要的是:始终为方法参数使用最小范围接口!这样,客户端拥有最大的*度,可以使用您的代码甚至不知道的类。
When an API method returns ArrayList
, I have absolutely no qualms with that, but when it demands an ArrayList
(or, all to common, Vector
) parameter, I consider hunting down the programmer and hurting him, because it means that I can't use Arrays.asList()
, Collections.singletonList()
or Collections.EMPTY_LIST
.
当一个API方法返回ArrayList时,我绝对没有任何疑虑,但是当它需要一个ArrayList(或者所有常见的Vector)参数时,我会考虑追捕程序员并伤害他,因为这意味着我不能使用Arrays.asList(),Collections.singletonList()或Collections.EMPTY_LIST。
#9
Sorry to disagree, but I think the basic rule is as follows:
抱歉不同意,但我认为基本规则如下:
- For input arguments use the most generic.
- For output values, the most specific.
对于输入参数,使用最通用的。
对于输出值,最具体。
So, in this case you want to declare the implementation as:
因此,在这种情况下,您希望将实现声明为:
public ArrayList<String> foo() {
return new ArrayList<String>();
}
Rationale: The input case is already known and explained by everyone: use the interface, period. However, the output case can look counter-intuitive. You want to return the implementation because you want the client to have the most information about what is receiving. In this case, more knowledge is more power.
理由:输入案例已为每个人所知并解释:使用界面,句点。但是,输出情况看起来可能违反直觉。您希望返回实现,因为您希望客户端获得有关接收内容的最多信息。在这种情况下,更多的知识就是更多的力量。
Example 1: the client wants to get the 5th element:
示例1:客户端想要获取第5个元素:
- return Collection: must iterate until 5th element vs return List:
- return List:
list.get(4)
return Collection:必须迭代直到第5个元素vs返回List:
return List:list.get(4)
Example 2: the client wants to remove the 5th element:
示例2:客户端想要删除第5个元素:
- return List: must create a new list without the specified element (
list.remove()
is optional). - return ArrayList:
arrayList.remove(4)
return List:必须创建一个没有指定元素的新列表(list.remove()是可选的)。
return ArrayList:arrayList.remove(4)
So it's a big truth that using interfaces is great because it promotes reusability, reduces coupling, improves maintainability and makes people happy ... but only when used as input.
因此,使用接口是一个很大的事实,因为它可以提高可重用性,减少耦合,提高可维护性并使人们满意......但仅在用作输入时。
So, again, the rule can be stated as:
因此,规则可以表述为:
- Be flexible for what you offer.
- Be informative with what you deliver.
灵活应对您的需求。
提供您所提供的信息。
So, next time, please return the implementation.
那么,下次请返回实施。
#10
You use interface to abstract away from the actual implementation. The interface is basically just a blueprint for what your implementation can do.
您使用接口来抽象实际实现。该接口基本上只是您的实现可以执行的操作的蓝图。
Interfaces are good design because they allow you to change implementation details without having to fear that any of its consumers are directly affected, as long as you implementation still does what your interface says it does.
接口是很好的设计,因为它们允许您更改实现细节,而不必担心任何消费者直接受到影响,只要您的实现仍然执行您的界面所说的。
To work with interfaces you would instantiate them like this:
要使用接口,您可以像这样实例化它们:
IParser parser = new Parser();
Now IParser would be your interface, and Parser would be your implementation. Now when you work with the parser object from above, you will work against the interface (IParser), which in turn will work against your implementation (Parser).
现在IParser将成为您的界面,而Parser将成为您的实现。现在,当您使用上面的解析器对象时,您将使用接口(IParser),这反过来将对您的实现(Parser)起作用。
That means that you can change the inner workings of Parser as much as you want, it will never affect code that works against your IParser parser interface.
这意味着您可以根据需要更改Parser的内部工作方式,它永远不会影响对您的IParser解析器接口起作用的代码。
#11
In general use the interface in all cases if you have no need of the functionality of the concrete class. Note that for lists, Java has added a RandomAccess marker class primarily to distinguish a common case where an algorithm may need to know if get(i) is constant time or not.
通常在所有情况下都使用接口,如果您不需要具体类的功能。请注意,对于列表,Java添加了一个RandomAccess标记类,主要用于区分算法可能需要知道get(i)是否为常量时间的常见情况。
For uses of code, Michael above is right that being as generic as possible in the method parameters is often even more important. This is especially true when testing such a method.
对于代码的使用,上面的迈克尔是正确的,在方法参数中尽可能通用甚至更重要。在测试这种方法时尤其如此。
#12
You'll find (or have found) that as you return interfaces, they permeate through your code. e.g. you return an interface from method A and you have to then pass an interface to method B.
您会发现(或已经发现)当您返回接口时,它们会渗透您的代码。例如从方法A返回一个接口,然后必须将接口传递给方法B.
What you're doing is programming by contract, albeit in a limited fashion.
你正在做的是通过合同编程,尽管是以有限的方式。
This gives you enormous scope to change implementations under the covers (provided these new objects fulfill the existing contracts/expected behaviours).
这为您提供了巨大的范围来更改封面下的实现(假设这些新对象满足现有合同/预期行为)。
Given all of this, you have benefits in terms of choosing your implementation, and how you can substitute behaviours (including testing - using mocking, for example). In case you hadn't guessed, I'm all in favour of this and try to reduce to (or introduce) interfaces wherever possible.
鉴于所有这些,您在选择实施方面有所裨益,以及如何替代行为(包括测试 - 例如使用模拟)。如果您没有猜到,我全都赞成这一点,尽量减少(或引入)接口。
#1
For instance, if I know that I will primarily access the data in the list randomly, a LinkedList would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList.
例如,如果我知道我将主要访问列表中的数据,则LinkedList会很糟糕。但是如果我的库函数只返回界面,我根本就不知道。为了安全起见,我甚至可能需要将列表显式复制到ArrayList。
As everybody else has mentioned, you just mustn't care about how the library has implemented the functionality, to reduce coupling and increasing maintainability of the library.
正如其他人提到的那样,您不必关心库如何实现功能,减少耦合并提高库的可维护性。
If you, as a library client, can demonstrate that the implementation is performing badly for your use case, you can then contact the person in charge and discuss about the best path to follow (a new method for this case or just changing the implementation).
如果您作为库客户端可以证明实现对您的用例表现不佳,那么您可以联系负责人并讨论要遵循的最佳路径(针对此案例的新方法或仅更改实施) 。
That said, your example reeks of premature optimization.
也就是说,你的例子充满了过早的优化。
If the method is or can be critical, it might mention the implementation details in the documentation.
如果该方法是或可能是关键的,它可能会提到文档中的实现细节。
#2
Return the appropriate interface to hide implementation details. Your clients should only care about what your object offers, not how you implemented it. If you start with a private ArrayList, and decide later on that something else (e.g., LinkedLisk, skip list, etc.) is more appropriate you can change the implementation without affecting clients if you return the interface. The moment you return a concrete type the opportunity is lost.
返回适当的接口以隐藏实现细节。您的客户应该只关心您的对象提供的内容,而不是您如何实现它。如果您从私有ArrayList开始,并稍后决定其他东西(例如,LinkedLisk,跳过列表等)更合适,则可以在不返回接口的情况下更改实现而不影响客户端。返回具体类型的那一刻,机会就会消失。
#3
In OO programming, we want to encapsulate as much as possible the data. Hide as much as possible the actual implementation, abstracting the types as high as possible.
在OO编程中,我们希望尽可能地封装数据。尽可能隐藏实际的实现,尽可能地抽象出类型。
In this context, I would answer only return what is meaningful. Does it makes sense at all for the return value to be the concrete class? Aka in your example, ask yourself: will anyone use a LinkedList-specific method on the return value of foo?
在这种情况下,我只会回答有意义的回报。将返回值作为具体类是否有意义?在你的例子中,Aka问自己:有人会在foo的返回值上使用特定于LinkedList的方法吗?
- If no, just use the higher-level Interface. It's much more flexible, and allows you to change the backend
- If yes, ask yourself: can't I refactor my code to return the higher-level interface? :)
如果不是,只需使用更高级别的接口即可。它更加灵活,允许您更改后端
如果是,请问自己:我不能重构我的代码以返回更高级别的界面吗? :)
The more abstract is your code, the less changes your are required to do when changing a backend. It's as simple as that.
您的代码越抽象,更改后端时您需要做的更改就越少。就这么简单。
If, on the other hand, you end up casting the return values to the concrete class, well that's a strong sign that you should probably return instead the concrete class. Your users/teammates should not have to know about more or less implicit contracts: if you need to use the concrete methods, just return the concrete class, for clarity.
另一方面,如果你最终将返回值转换为具体类,那么这是一个强烈的迹象,表明你应该返回具体的类。您的用户/团队成员不应该了解更多或更少的隐式合同:如果您需要使用具体方法,只需返回具体类,以便清楚。
In a nutshell: code abstract, but explicitly :)
简而言之:代码摘要,但显式:)
#4
In general, for a public facing interface such as APIs, returning the interface (such as List
) over the concrete implementation (such as ArrayList
) would be better.
通常,对于面向公众的接口(例如API),在具体实现(例如ArrayList)上返回接口(例如List)会更好。
The use of a ArrayList
or LinkedList
is an implementation detail of the library that should be considered for the most common use case of that library. And of course, internally, having private
methods handing off LinkedList
s wouldn't necessarily be a bad thing, if it provides facilities that would make the processing easier.
使用ArrayList或LinkedList是库的实现细节,应该考虑该库的最常见用例。当然,在内部,让私人方法交出LinkedLists不一定是坏事,如果它提供的设施可以使处理更容易。
There is no reason that a concrete class shouldn't be used in the implementation, unless there is a good reason to believe that some other List
class would be used later on. But then again, changing the implementation details shouldn't be as painful as long as the public facing portion is well-designed.
没有理由不在实现中使用具体类,除非有充分的理由相信稍后将使用其他List类。但话说回来,只要面向公众的部分设计得很好,改变实施细节就不会那么痛苦。
The library itself should be a black box to its consumers, so they don't really have to worry about what's going on internally. That also means that the library should be designed so that it is designed to be used in the way it is intended.
图书馆本身应该是消费者的黑盒子,因此他们不必担心内部会发生什么。这也意味着应该对库进行设计,使其按照预期的方式使用。
#5
Without being able to justify it with reams of CS quotes (I'm self taught), I've always gone by the mantra of "Accept the least derived, return the most derived," when designing classes and it has stood me well over the years.
如果没有能够用大量的CS引用来证明它(我是自学成才的话),在设计课程时,我总是遵循“接受最少派生,回归最多派”的口号,这让我很好这些年。
I guess that means in terms of interface versus concrete return is that if you are trying to reduce dependencies and/or decouple, returning the interface is generally more useful. However, if the concrete class implements more than that interface, it is usually more useful to the callers of your method to get the concrete class back (i.e. the "most derived") rather than aribtrarily restrict them to a subset of that returned object's functionality - unless you actually need to restrict them. Then again, you could also just increase the coverage of the interface. Needless restrictions like this I compare to thoughtless sealing of classes; you never know. Just to talk a bit about the former part of that mantra (for other readers), accepting the least derived also gives maximum flexibility for callers of your method.
我想这意味着在接口与具体返回方面,如果你试图减少依赖关系和/或解耦,返回接口通常更有用。但是,如果具体类实现的不仅仅是那个接口,那么对于方法的调用者来说,通常更有用的是获取具体类(即“最派生”),而不是将它们无条件地限制为返回对象的功能的子集。 - 除非你真的需要限制它们。然后,您还可以增加界面的覆盖范围。像这样的不必要的限制我比较无意义的类密封;你永远都不会知道。只是谈谈该咒语的前一部分(对于其他读者),接受最少派生也为您的方法的调用者提供了最大的灵活性。
-Oisin
#6
As a rule, I only pass back internal implementations if I am in some private, inner workings of a library, and even so only sparingly. For everything that is public and likely to be called from the outside of my module I use interfaces, and also the Factory pattern.
作为一项规则,如果我在库的某些私有内部工作中,我只会传回内部实现,即使只是谨慎。对于所有公共的,可能从我的模块外部调用的东西,我使用接口,以及Factory模式。
Using interfaces in such a way has proven to be a very reliable way to write reusable code.
以这种方式使用接口已被证明是编写可重用代码的一种非常可靠的方法。
#7
The main question has been answered already and you should always use the interface. I however would just like to comment on
已经回答了主要问题,您应该始终使用界面。不过我想评论一下
It is obvious that using the interface has a lot of advantages (that's why it's there). In most cases it doesn't really matter what concrete implementation is used by a library function. But maybe there are cases where it does matter. For instance, if I know that I will primarily access the data in the list randomly, a LinkedList would be bad. But if my library function only returns the interface, I simply don't know. To be on the safe side I might even need to copy the list explicitly over to an ArrayList.
很明显,使用界面有很多优点(这就是它的原因)。在大多数情况下,库函数使用的具体实现并不重要。但也许有些情况确实很重要。例如,如果我知道我将主要访问列表中的数据,则LinkedList会很糟糕。但是如果我的库函数只返回界面,我根本就不知道。为了安全起见,我甚至可能需要将列表显式复制到ArrayList。
If you are returning a data structure that you know has poor random access performance -- O(n) and typically a LOT of data -- there are other interfaces you should be specifying instead of List, like Iterable so that anyone using the library will be fully aware that only sequential access is available.
如果你要返回的数据结构你知道它的随机访问性能很差 - O(n)并且通常有很多数据 - 你应该指定其他接口而不是List,比如Iterable,这样任何使用该库的人都会充分意识到只有顺序访问可用。
Picking the right type to return isn't just about interface versus concrete implementation, it is also about selecting the right interface.
选择正确的类型返回不仅仅是关于接口与具体实现,还有关于选择正确的接口。
#8
It doesn't matter all that much whether an API method returns an interface or a concrete class; despite what everyone here says, you almost never change the implementiation class once the code is written.
API方法是返回接口还是具体类并不重要;尽管这里的每个人都说过,但一旦代码编写完成,你几乎从不改变实现类。
What's far more important: always use minimum-scope interfaces for your method parameters! That way, clients have maximal freedom and can use classes your code doesn't even know about.
更重要的是:始终为方法参数使用最小范围接口!这样,客户端拥有最大的*度,可以使用您的代码甚至不知道的类。
When an API method returns ArrayList
, I have absolutely no qualms with that, but when it demands an ArrayList
(or, all to common, Vector
) parameter, I consider hunting down the programmer and hurting him, because it means that I can't use Arrays.asList()
, Collections.singletonList()
or Collections.EMPTY_LIST
.
当一个API方法返回ArrayList时,我绝对没有任何疑虑,但是当它需要一个ArrayList(或者所有常见的Vector)参数时,我会考虑追捕程序员并伤害他,因为这意味着我不能使用Arrays.asList(),Collections.singletonList()或Collections.EMPTY_LIST。
#9
Sorry to disagree, but I think the basic rule is as follows:
抱歉不同意,但我认为基本规则如下:
- For input arguments use the most generic.
- For output values, the most specific.
对于输入参数,使用最通用的。
对于输出值,最具体。
So, in this case you want to declare the implementation as:
因此,在这种情况下,您希望将实现声明为:
public ArrayList<String> foo() {
return new ArrayList<String>();
}
Rationale: The input case is already known and explained by everyone: use the interface, period. However, the output case can look counter-intuitive. You want to return the implementation because you want the client to have the most information about what is receiving. In this case, more knowledge is more power.
理由:输入案例已为每个人所知并解释:使用界面,句点。但是,输出情况看起来可能违反直觉。您希望返回实现,因为您希望客户端获得有关接收内容的最多信息。在这种情况下,更多的知识就是更多的力量。
Example 1: the client wants to get the 5th element:
示例1:客户端想要获取第5个元素:
- return Collection: must iterate until 5th element vs return List:
- return List:
list.get(4)
return Collection:必须迭代直到第5个元素vs返回List:
return List:list.get(4)
Example 2: the client wants to remove the 5th element:
示例2:客户端想要删除第5个元素:
- return List: must create a new list without the specified element (
list.remove()
is optional). - return ArrayList:
arrayList.remove(4)
return List:必须创建一个没有指定元素的新列表(list.remove()是可选的)。
return ArrayList:arrayList.remove(4)
So it's a big truth that using interfaces is great because it promotes reusability, reduces coupling, improves maintainability and makes people happy ... but only when used as input.
因此,使用接口是一个很大的事实,因为它可以提高可重用性,减少耦合,提高可维护性并使人们满意......但仅在用作输入时。
So, again, the rule can be stated as:
因此,规则可以表述为:
- Be flexible for what you offer.
- Be informative with what you deliver.
灵活应对您的需求。
提供您所提供的信息。
So, next time, please return the implementation.
那么,下次请返回实施。
#10
You use interface to abstract away from the actual implementation. The interface is basically just a blueprint for what your implementation can do.
您使用接口来抽象实际实现。该接口基本上只是您的实现可以执行的操作的蓝图。
Interfaces are good design because they allow you to change implementation details without having to fear that any of its consumers are directly affected, as long as you implementation still does what your interface says it does.
接口是很好的设计,因为它们允许您更改实现细节,而不必担心任何消费者直接受到影响,只要您的实现仍然执行您的界面所说的。
To work with interfaces you would instantiate them like this:
要使用接口,您可以像这样实例化它们:
IParser parser = new Parser();
Now IParser would be your interface, and Parser would be your implementation. Now when you work with the parser object from above, you will work against the interface (IParser), which in turn will work against your implementation (Parser).
现在IParser将成为您的界面,而Parser将成为您的实现。现在,当您使用上面的解析器对象时,您将使用接口(IParser),这反过来将对您的实现(Parser)起作用。
That means that you can change the inner workings of Parser as much as you want, it will never affect code that works against your IParser parser interface.
这意味着您可以根据需要更改Parser的内部工作方式,它永远不会影响对您的IParser解析器接口起作用的代码。
#11
In general use the interface in all cases if you have no need of the functionality of the concrete class. Note that for lists, Java has added a RandomAccess marker class primarily to distinguish a common case where an algorithm may need to know if get(i) is constant time or not.
通常在所有情况下都使用接口,如果您不需要具体类的功能。请注意,对于列表,Java添加了一个RandomAccess标记类,主要用于区分算法可能需要知道get(i)是否为常量时间的常见情况。
For uses of code, Michael above is right that being as generic as possible in the method parameters is often even more important. This is especially true when testing such a method.
对于代码的使用,上面的迈克尔是正确的,在方法参数中尽可能通用甚至更重要。在测试这种方法时尤其如此。
#12
You'll find (or have found) that as you return interfaces, they permeate through your code. e.g. you return an interface from method A and you have to then pass an interface to method B.
您会发现(或已经发现)当您返回接口时,它们会渗透您的代码。例如从方法A返回一个接口,然后必须将接口传递给方法B.
What you're doing is programming by contract, albeit in a limited fashion.
你正在做的是通过合同编程,尽管是以有限的方式。
This gives you enormous scope to change implementations under the covers (provided these new objects fulfill the existing contracts/expected behaviours).
这为您提供了巨大的范围来更改封面下的实现(假设这些新对象满足现有合同/预期行为)。
Given all of this, you have benefits in terms of choosing your implementation, and how you can substitute behaviours (including testing - using mocking, for example). In case you hadn't guessed, I'm all in favour of this and try to reduce to (or introduce) interfaces wherever possible.
鉴于所有这些,您在选择实施方面有所裨益,以及如何替代行为(包括测试 - 例如使用模拟)。如果您没有猜到,我全都赞成这一点,尽量减少(或引入)接口。