为什么使用接口(例如Map)而不是实现(HashMap)来定义Java对象


17

在大多数Java代码中,我看到人们这样声明Java对象:

Map<String, String> hashMap = new HashMap<>();
List<String> list = new ArrayList<>();

代替:

HashMap<String, String> hashMap = new HashMap<>();
ArrayList<String> list = new ArrayList<>();

为什么偏爱使用接口而不是实际使用的实现来定义Java对象?


Answers:


26

原因是这些接口的实现通常在处理它们时是不相关的,因此,如果您要求调用者将a传递HashMap给方法,那么您实际上就必须使用哪种实现。因此,一般来说,您应该处理其接口而不是实际的实现,并避免可能导致不得不使用以下方法更改所有方法签名的痛苦和痛苦:HashMap当您决定需要时LinkedHashMap

应该说,与实施相关的情况是有例外的。如果在顺序很重要时需要地图,则可以要求传递a TreeMap或a LinkedHashMap,或者最好传递SortedMap一个不指定特定实现的形式。这迫使调用者必须通过某种类型的Map实现,并强烈暗示顺序重要。就是说,您能否覆盖SortedMap并传递未分类的邮件吗?是的,当然可以,但是期望发生坏的事情。

但是,最佳实践仍然表明,如果这并不重要,则不应使用特定的实现。总的来说,这是正确的。如果要处理继承DogCat派生于的方法Animal,以便充分利用继承,通常应避免使用特定于Dog或的方法Cat。宁可使用中的所有方法,DogCat应该覆盖其中的方法Animal,从长远来看,它将为您节省麻烦。


当您需要对地图进行排序时,参数类型应为SortedMap,而不是TreeMap
Cephalopod 2014年

@Arian SortedMap是处理订购的几种实现之一。那不是重点。 TreeMap还可以根据键的实现Comparable或给定Comparator接口来订购商品。
尼尔

不,SortedMap不是实现,这就是重点。它是按键排序的地图的界面。
Cephalopod

1
@Arian Ah我明白你的意思了。是的,更好的SortedMap,因为它不会强制实现。我会做适当的调整。
尼尔2014年

实际上,a LinkedHashMap没有实现SortedMap。的唯一子类SortedMapConcurrentSkipListMapTreeMap
bcorso 2014年

10

用莱曼的话说:

电力设备制造商使用电插头而不是简单地剥开电缆来制造产品的原因也与此相同,而房屋则配备了壁式插座,而不是将电缆从墙上剥下。

通过使用标准插头,它们可以将相同的插头插入房屋周围的任何兼容插头。

从墙上插座的角度来看,插入电视机还是立体声都没关系。

这使得设备和插座都更加有用。

例如,接受Map作为参数的方法。

只要您将HashMap或LinkedHashMap传递给它,该方法就将起作用,只要它是Map的子类即可。

这就是李斯科夫替代原则

在您提供的示例代码中,这意味着您以后可以出于某种原因更改Hash的具体实现,而无需更改其余代码。

软件的问题在于,由于以后相对容易地进行更改而又不浪费砖块或灰泥,因此人们认为这种前瞻性的想法是不值得的。但是现实告诉我们软件维护非常昂贵。


4

遵循接口隔离原则SOLID中的“ I”)。它可以防止使用那些对象的代码依赖于不需要的那些对象的方法,从而使代码更少耦合,因此更易于更改。

例如,如果以后发现确实需要LinkedHashMap,可以安全地进行更改,而不会影响任何其他代码。

但是,这是一个折衷方案,因为您人为地限制了可以将对象作为参数的代码。说有一个函数的地方,需要一个HashMap出于某种原因。如果返回Map,则无法将对象传递给该函数。您必须权衡将来某个时候需要更具体的类中的额外功能与限制耦合并保持公共接口尽可能小的愿望之间的平衡。


3

将变量约束到接口可确保该变量的任何用法都不会被使用 HashMap接口上可能不存在的特定功能,因此只要新实例也实现了该实例,就可以稍后将实例更改为其他实现而无需担心接口。

因此,无论何时要使用对象接口,始终将变量声明为接口而不是特定的实现始终是一种好习惯,这适用于您可能使用的具有接口的所有类型的对象。您经常看到它的原因是许多人已经习惯了这种习惯。

就是说,有时退出使用接口并没有什么害处,而且我们中的大多数人并非总是草率地遵循此规则,而没有真正的危害。当您感觉代码可能会更改并且将来需要维护/增长时,最好坚持这样做。当您使用您认为不会长寿或具有重要意义的代码进行黑客攻击时,不必担心。同样,违反此规则通常会有一个小的后果,那就是将实现更改为另一个实现可能需要进行一些重构,因此,即使您不总是遵循它,也不会给自己造成很大的伤害,尽管遵循它也没有真正的危害。 。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.