关于java:我什么时候想在实际的类中声明接口?

When do I want to declare interface over the actual class?

例如,我经常看到:

1
2
3
Set<Integer> s = new TreeSet<Integer>();
Set<Integer> s = new HashSet<Integer>();
Map<Integer, String> m = new HashMap<Integer, String>();

结束

1
2
3
TreeSet<Integer> ts = new TreeSet<Integer>();
HashSet<Integer> hs = new HashSet<Integer>();
HashMap<Integer, String> hm = new HashMap<Integer, String>();

前者与后者的优势/劣势是什么?


对我来说,这可以归结为几点。

你关心实施吗?您的代码需要知道MapHashMap还是TreeMap吗?或者只是关心它是否有某种键/值结构

它还意味着,当我构建实现代码时,如果我公开一个返回map的方法,我可以在不影响任何依赖它的代码的情况下随时间更改实现(因此,尝试和强制转换这些类型的值是一个坏主意的原因)。

另一个原因是,在代码周围移动这些结构变得更容易,这样任何可以接受Map的方法都比依赖HashMap的方法更容易处理。

约定(我遵循)基本上是使用满足API需求的最低功能接口。使用不提供API所需功能的接口是没有意义的(例如,如果您需要一个SortedMap,那么使用Map就没有意义了)

IMHO


你应该阅读理解数据抽象,威廉·R·库克重温了这本书,以及他关于"对象"和"面向对象"的简化、现代定义的建议。

基本上:如果使用Java类作为工厂以外的任何东西,也就是说,如果在EDCOX1×7×操作符之后,任何地方都有一个类名,那么您就不做面向对象编程。遵循这条规则并不能保证您正在进行OO,但是违反这条规则意味着您没有这样做。

注意:不做OO没有什么问题。


通常,您希望声明具有实际使用行为的最一般的类型。这样,如果您决定采用不同的具体类,就不必更改那么多的代码。你可以让这个功能的用户更自由。


应用程序的维护成本是开发成本的三倍。这意味着您希望代码尽可能简单和清晰。

如果您使用列表而不是ArrayList,那么您将清楚地表明您没有使用任何对ArrayList特殊的方法,并且可以从另一个列表实现中更改它。在不必使用数组列表的情况下使用数组列表的问题是,要安全地确定它是否真的是一个列表需要很长时间。也就是说,很难证明你从不需要什么。(添加内容比删除内容相对容易)

一个类似的例子是在列表执行时使用向量。如果您看到您所说的向量;开发人员出于一个好的原因选择了一个向量,那么它是线程安全的。但我现在需要更改它并检查代码是否是线程安全的。你会说,但是我看不到它是如何以多线程的方式使用的,所以我必须检查所有可能使用它的方法,或者当我迭代它时,当它实际上不需要线程安全时,是否需要添加synchronized。在不需要时使用线程安全收集不仅浪费CPU时间,更重要的是浪费开发人员的时间。