2010-06-25 62 views
5

如何設計涉及其他類集合的類?包含其他類集合的類的設計(操作方法)

一般示例:

工作區包含項目的數目。
A 項目包含大量的資源
每個資源可能包含大量的文件

所以這裏確定的類可以是Workspace,Project,Resource和File。 工作區將具有Project.Project列表將有資源和資源列表將具有文件列表。當然,每個班都有其相關的設置。

現在的基本問題是:
a)誰創建並添加一個類到特定的集合?另一個類或包含集合的類?
b)還有如何跟蹤特定的集合以及如何存儲它們?
c)誰審覈特定收藏的變化?
d)在這種情況下可以應用哪些不同的設計模式?

基本上我想減少不同類之間的耦合。

謝謝大家

+0

我也有一個相關的問題,我在這裏添加.. http://stackoverflow.com/questions/3186632/a-design-for-adding-resources-to-a-project – Amitd 2010-07-06 15:24:44

回答

5

有很多種關係的 - 考慮

  • 汽車和車輪
  • 汽車和司機
  • 汽車和註冊船東
  • 客戶和訂單和訂購專線
  • 學校和班級及實例

如果你看看UML建模你會看到與相關對象的生命週期Aggegration和組成與問題之間爲基數等概念,方向和distictions。

因此,我們需要一系列技術和模式來處理不同類型的關係,這並不讓人感到意外。

關於d)。有一個重要原則Law of Demeter或最少知識原則。

然後一個重要的技術是,封裝通過隱藏信息減少耦合。汽車對人的許多細節可能沒什麼興趣,所以我們可能在Person類上有一個IDriver接口,IDriver提供了汽車關心的特定方法。一般原則是傾向於編程接口。

接下來,我們可以考慮a)。創建。由於我們傾向於使用接口,因此使用Factory模式通常是有意義的。這確實留下了誰叫工廠的問題。我們喜歡:

IPerson aPerson = myAutomobile.createDriver(/* params */); 

IPerson aPerson = aPersonFactory.create(/* params */); 
    myAutomobile.addDriver(aPerson); 

在這裏,我認爲這是很明顯,汽車不很瞭解的人,因此第二是責任分工更合理。然而也許訂單可以合理地創建OrderLines,類創建ClassInstances? b)。注意動向?這就是爲什麼我們有豐富的Collection類。使用哪些取決於關係的性質(一對一,多對一等)以及我們如何使用它。所以我們根據需要選擇Arrays和HashMaps等。對於汽車/車輪,我們甚至可以使用汽車的名稱屬性 - 畢竟汽車有六個車輪(frontLeft,frontRight,backLeft,backRight,spare和steering)。如果通過「存儲」你的意思是堅持下去,那麼我們正在關注關係數據庫中的外鍵技術。 RDBMS和內存中對象之間的映射越來越多地由良好的持久性機制(如JPA)來管理。 c)。審計?我沒有看到審計專門適用於關係層面。顯然汽車.addDriver()方法可能是任意複雜的。如果有業務需求來審計這個行爲,那麼很明顯這是一個體面的地方。這只是圍繞着誰擁有這些信息的標準OO設計問題。一般原則:「不要重複自己」非常清楚,我們不希望每個調用addDriver()的對象都需要記住進行審計,因此它是Auto的工作。

1

創建良好的面向對象設計有點藝術形式,但有一些校長需要牢記。

想想你的用戶將如何使用你的界面。 誰是你的用戶?僅僅是你,爲了一個特定的目的,還是你爲不同的客戶設計了一些東西。界面設計很難,但想想你的用戶如何真正想要使用你的界面的真實例子。一個好的方法是編寫測試,這會迫使你使用自己的東西。另一種方法是查看現有的庫,做同樣的事情,看看它們是如何使用的。

讓事情變得簡單,愚蠢。 也就是說,從呼叫者的角度來看,它們很簡單。這適用於封裝,您應該只根據需要公開內部實現。它適用於創建易於理解的一致界面。這意味着你應該避免爲每一個可以想象的階級製作一個對象的陷阱,製造大量的屬性,並儘可能地通用。最後一點是特別重要的一點;作爲開發人員,我們的優勢在於我們有能力進行推測和抽象,但正因爲如此,我們經常陷入使系統大量超出需求的陷阱。

想想所有權。 每個對象將由另一個擁有,這意味着它應該作爲該對象的一部分被創建和銷燬,或者將被另一個對象引用。你應該相應地設計你的界面。所有權是一種耦合形式,但它通常是正確的設計。它確實簡化了您的界面,以及您的呼叫者維護自己的對象的負擔。

雖然應該知道並使用你的收藏庫。 瞭解您正在使用的任何語言/框架的集合庫,並使用它們。另外,請嘗試在命名和行爲方面使自己的接口與這些庫保持一致。

關於審計。 你可以做一些審計(日誌記錄,保持統計)從你的類中,但如果你審計的需求是複雜的(需要的時候知道你的數據的變化),這可能是最好使用Observer模式。

2

在設計軟件時我發現它有用來看待事物從一種類型的理論點,順其自然我。

工作區是類型的項目+項目^ 2 +項目^ 3 ...(意爲無論是項目列表真正工作區的真實

同樣,

一個項目的類型爲資源+資源^ 2 +資源^ 3 ...

甲資源是型文件+文件的^ 2 +費爾E 1 3 ...

所以在像C#語言†可以定義你工作臺類正是如此:

public class WorkSpace : IList<Project> //the important thing here is that you're declaring that things that are true for a list of Projects is true for a WorkSpace. The WorkSpace class may in fact do other stuff too... 
{ 

} 

和類似的其他類。

然後在你的客戶端代碼,你會使用這樣的:

foreach (var project in WorkSpace) 
{ 
    //do stuff 
} 

Projects.Add(new Resource() { file1, file2, file3, file4, /* etc */}); 

想想類型和它們之間的關係第一次。封裝是一個低層次的家務理念。原則是保持相關的代碼靠近在一起,而不相關的代碼相距甚遠(如果相隔很遠,則意味着在某種邊界(例如函數或類或任何其他語言可能提供的邊界概念)之間或之後)。

†從張貼的歷史我猜測,你熟悉C#,但是這也適用於其他語言。

+2

+1工作區: IList '方法。從未想過這樣做。 – 2010-06-26 08:15:31

+3

優先在這裏繼承遏制。工作區是不是真正的在這個意義上項目的清單,你會希望能夠替代工作區每次使用的項目清單的地方;此外,工作區也可能是許多其他內容的列表,如項目設置列表和用戶首選項列表。使用遏制意味着更好的封裝和更簡單的用戶界面。 – nas 2010-06-26 08:21:55

+0

@nstoertz您可以使WorkSpace成爲IList 和IList ,因爲您正在實現一個接口(儘管我可能不會實現這些其他接口)。你所說的是,對於工作臺而言,項目列表中的所有內容都是真實的,但工作空間的情況對於項目列表可能並非如此。另外,雖然實現繼承可能是危險的(我希望非抽象類被默認封裝),但接口繼承是相當安全且沒有爭議的。 – 2010-06-26 08:28:01

相關問題