2010-02-07 38 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。

相關問題