2015-11-01 74 views
3

這可能是一件非常簡單的事情,但我似乎無法自行解決這個問題。使用構圖時,訪問「內部對象」方法的最佳方式是什麼?我能夠解決的每一個方法似乎都違反了一些OO原則或其他原則。使用組合訪問對象方法?

這是一個非常廣泛的話題,但我會包括一個例子,只是爲了讓事情變得清晰。代碼用java編寫,但我相信這個問題幾乎適用於使用OOP的任何語言。

Class Shelf { 
    private Book book; 
} 

Class Book { 
    public void turnPage() { 
     //do stuff 
    } 
} 

當您只能訪問Shelf對象時訪問Book方法的最佳方法是什麼?我讀過的一些地方提出了Shelf內的包裝方法,因爲它遵循Demeter法則。但是,這似乎並不是每個案例的最佳選擇。

首先,許多內部對象的方法可能與main類無關,因此如果主類爲每個方法實現包裝器並沒有任何意義,並且很可能會破壞Single責任原則。此外,如果內部對象被用於大量其他類的組合,所有需要做同樣的事情,它會導致大量的不必要的代碼重複,使您的代碼更少DRY。

我的第一個直覺是有一個簡單的getBook()方法,可以訪問本書來直接操作這些方法。從書架上翻開書頁並翻開書頁更有意義,而不是告訴書架爲你翻書。然而,這似乎破壞了封裝和德米特法。如果我要將圖書變量公開爲最終版本,也是如此。

我錯過了什麼嗎?還是過於複雜?我似乎無法圍繞這一點,所以我非常感謝一些幫助。

回答

2

在這種情況下,很可能你會在書架上放置書籍而不是書籍。對於我來說,通過貨架上獨一無二的標識來返回特定的書籍並對其進行操作是非常有意義的。

在這種情況下,我會避免返回那些違反封裝和德米特法則的書籍集合。

因此,舉例來說:

public class Shelf { 
    private Map<Long, Book> books = new HashMap(); 

    // Class Code 

    public Book getBook(Long id) { 
     return books.get(id); 
    } 
} 

像這樣的事情不會破壞封裝,因爲你不暴露類的內部。如果您希望使用列表而不是地圖,那麼課外的任何地方都應該受到變化的影響。

而且,在這種情況下,返回該書是有意義的,而不是在Shelf類中創建方法turnPage()。這就好像你在Book中有一個屬性name,這是一個字符串類型。你不會在Book中創建一個方法nameSubstring()只是爲了在name上操作,對吧?那麼爲什麼你要在Book上創建一個turnPage()

+0

雖然我同意這一點,這是不是還違反了德米特法?這同樣適用於單個對象而不是對象集合的情況嗎? – Azk

+1

我不覺得它違反了LoD,因爲你沒有公開'Shelf'的內部結構,你只需使用'Shelf'作爲訪問者,這就是主要思想。考慮將書籍作爲查詢的結果返回給「Shelf」,而不是將內容暴露給內部 – Avi