2010-02-07 37 views
2

我在文本中看到了一个这样的例子,并不确定他们为什么这样做。比方说,你是从数据库中获取了一堆苹果对象:为什么将数据库'Apples'读入列表而不是ArrayList,Vector或LinkedList?

List<Apple> appleList = (List<Apple>) db.getApples() 

为什么你会投给List<Apple>,而不是具体的列表类型(ArrayList中,向量或链表)中的一个?

+3

演员根本没有必要。 – 2010-02-07 17:42:47

+3

@PartlyCloudy:你怎么知道没有看到'db.getApples()'看起来像什么? – skaffman 2010-02-07 17:56:33

+0

@skaffman:嗯,这是一个扩展的引用转换,只要它引用'java.util.List' – 2010-02-07 18:11:50

回答

2

这个关于Liskov Substitution PrincipleInterface Segregation Principle的wiki文章可能会帮助你理解为什么你应该编程接口。

当跨EE开发中常见的领域工作时,您多次不关心正在使用何种类型的集合。你往往不仅仅是想从中取回某些东西,迭代它或删除一些东西。这些都不需要知道你正在处理的是什么类型的实现。它也可以很容易地切换出底层的实现。例如,假设我正在处理项目并将数据库中的项目列表加载到ArrayList中。在其他地方的代码我循环通过此列表:

class DBUtil { 
    public static ArrayList<Item> getMeAllOfMyItems() { 
     return items; // load from database whatever... 
    } 
} 

... ...同时

ArrayList<Item> items = DBUtil.getMeAllOfMyItems(); 
for (int i = 0; i < items.size(); i++) { 
    // do something with item 
} 

现在,让我们说,我决定使用链表来代替。我将不得不改变,从数据库加载的一切方法,以及我使用来遍历它的代码:

class DBUtil { 
    public static LinkedList<Item> getMeAllOfMyItems() { 
     return items; // load from database whatever... 
    } 
} 

... ...同时

LinkedList<Item> items = DBUtil.getMeAllOfMyItems(); 
for (int i = 0; i < items.size(); i++) { 
    // do something with item 
} 

这是两个变化。如果我原本是这么写的:

class DBUtil { 
    public static List<Item> getMeAllOfMyItems() { 
     return items; // load from database whatever... 
    } 
} 

...与此同时...

List<Item> items = DBUtil.getMeAllOfMyItems(); 
for (int i = 0; i < items.size(); i++) { 
    // do something with item 
} 

我只会不得不改变一个方法,在这里我返回从数据库中的项目的方法。

更妙的是改变我遍历项目使用每个样式的方式:

class DBUtil { 
    public static List<Item> getMeAllOfMyItems() { 
     return items; // load from database whatever... 
    } 
} 

... ...同时

List<Item> items = DBUtil.getMeAllOfMyItems(); 
for (Item i : items) { 
    // do something with item 
} 

现在,如果我想,我甚至可以更改更多的实现,只要我使用的实现Iterable,我甚至不关心底层系统正在使用什么类型的Collection。

您应该努力使事物尽可能通用,意图是您不希望因其他地方的小改动而更改3或4个文件。

0

List只是一个接口,而ArrayListLinkedList是实现。根据 Joshua Bloch - Effective Java(条款18; 19),在这里使用接口总是更好。因此,您可以轻松切换实施。

0

大部分时间你都不知道数据库所属的API返回的List的确切实现。它可能是Java SE中的标准实现之一,也可能是API的自定义实现。

5

方法db.getApples()的用户应该不在乎这是否是ArrayListLinkedList等。这是一个实现细节。

在构建数据结构时,应该只指定数据结构的具体类型。之后,您应该参考适合您需求的界面。

通过这种方式,您可以毫无困难地更改数据结构的具体类型。

0

通常使用通用接口是一种更好的方法。这样,底层的实现可以决定哪种具体类型最适合这项工作。这也使得使用mock进行测试变得更加容易。

0

因为在Java中您应该编码为接口而不是实现

这样做可以让库代码的作者选择最适合的列表实现,而且你并不在乎。如果这样做,那么将该列表复制到具有所需属性的列表实现中。例如,如果您需要O(1)获取时间,请复制到ArrayLIst。

相关问题