2011-07-11 49 views
3

我正在構建一個需要許多具有類似屬性(例如:學生,教師,聯繫人,用戶)的子類的應用程序。性能將會有相當大的重疊,但也有很多不同之處。例如,一個人可能是學生,聯繫人和用戶。這裏是(限清晰度)的例子:對於多個類似的類,什麼被認爲是好的設計

Person 
    FirstName 
    LastName 
    DOB 
    CurrentAge 

Student <- Person 
    StudentId 
    Average 
    Email 
    Phone 

Contact <- Person 
    Email 
    Phone 
    Address 

User <- Person 
    Email 
    UserName 
    DOB 
    CurrentAge 

我想避免編寫代碼多次 - 例如:電子郵件驗證碼,計算年齡所需的代碼等。此外,我們很可能不得不增加其他課程稍後會有類似的重疊和差異。

什麼被認爲是處理這個問題的好設計,或者什麼樣的設計模式(如果有)涵蓋了這個?

從我對設計模式的基本理解來看,Decorator看起來不正確b/c我沒有添加行爲。複合不正確的B/C它不是遞歸的。我也明白,這可能不是一個理想的模式,但是,這似乎是一個非常普遍的要求。

如果很重要,這將主要用於ASP.NET/C#/VB.NET。

其他SO問題有兩個相似的類/對象(通常是子類)的答案,但我找不到任何類似的任意數量的類。

關於關聯數據庫設計的任何建議也是受歡迎的。

+0

我似乎無法接受兩個答案是正確的,但我的最終解決方案將incoroporate組成建議從保羅Sonier來處理存儲數據和驗證數據本身,從界面和角色的建議@Don Robby處理重疊屬性(實現多個接口)和邏輯(驗證IContact至少指定一個聯繫方法的角色)。 –

回答

4

你想使用組合來組合多個不同類的功能。您真正需要的是如何設計對象層次結構,以便您可以根據需要定義不同級別的功能。最好也是最簡單的方法是使用Composition來定義功能。

例如,在您的示例中,Person不需要電子郵件地址;然而,Contact確實和User確實;他們都從Person繼承。處理這個問題的方法是有一個Email類,然後你的ContactUser類可以有;該類可以管理驗證等。如果您確實希望將Email附加到Person,則可以使用PersonWithEmail類(請選擇一個更好的名稱,請!),它繼承自Person,並且構成繼承的PersonEmail class;這樣,從PersonWithEmail繼承的任何類將獲得Person功能和Email功能。然而,這種方法的問題在於,你直接在你的繼承層次結構中定義你的組合;這可能不是期望的。直接組合方法更簡單。

+1

謝謝保羅! 「直接構圖方法」是什麼意思?你是指自己製作屬性類型類?如果是這樣,那我就是用電子郵件,地址,電話和其他一些東西來做的。我似乎無法弄清楚的是如何制定不同的規則(例如:聯繫人必須有電話,地址,電子郵件,但學生必須有電子郵件和電話)。任何提示? –

0

對於所有不同的屬性,您可以在Person類中存儲存儲,並且可以爲屬性可訪問的不同類型的人提供子類。這樣,學生和聯繫人的Phone屬性可以具有相同的存儲空間。

您可以擁有子類型的標誌以及將某人作爲子類型的屬性。

例子:

public class Person { 

    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string DOB { get; set; } 
    public int CurrentAge { get; set; } 

    private string _studentId; 
    private double _average; 
    private string _email; 
    private string _phone; 

    public bool IsStudent { get; private set; } 

    public Student AsStudent { 
    get { 
     if (IsStudent) { 
     return this as Student; 
     } else { 
     throw new Exception("This Person is not Student."); 
     } 
    } 
    } 

} 

public class Student : Person { 
    public string StudentId { get { return _studentId; } set { _studentId = value; } } 
    public double Average { get { return _average; } set { _average = value; } } 
    public string Email { get { return _email; } set { _email = value; } } 
    public string Phone { get { return _phone; } set { _phone = value; } } 
} 

用法:

Person someone = GetStudentSomehow(...); 
Console.WriteLine(someone.FirstName); 
Console.WriteLine(someone.AsStudent.Phone); 
+0

謝謝Guffa。但是,我喜歡這樣,每次添加一個新類似的課程時,我都不需要更改我的Person界面(即添加IsTeacher,AsTeacher)? –

+0

@Jens Ehrich:是的。您當然可以將訪問權限放在子類中,但是使用起來會比較麻煩,即'Teacher.PersonIsTeacher(someone)'。此外,您仍然需要在Person類中添加任何其他屬性的存儲。 – Guffa

0

我會反對使用子類化這個根本,原因有二:

  • 一個人能理智是學生,聯繫人和用戶同時進行。
  • 一個人可以是現在的學生和教師,明年(和研究生,都在一次...)

把實際在Person類識別一個人的事。 將與該人正在扮演的角色分開的所有內容分離出來,可能爲Role,並創建其子類或實現。

允許一個人擁有多個角色,將Person類中的字段放入Set的對象中,該字段包含Role對象。

+0

謝謝唐。你能舉一個例子,說明這將如何與重疊的屬性,如電子郵件?即使該人有許多需要電子郵件的角色,我也只想存儲一個電子郵件地址。 –

0

如果可以說類是跟隨關係,則使用子類Tiger「」動物,否則它可能是一團糟,維持如此龐大的層次結構類添加新行爲。

此外,不要忘記將基類設置爲abstract,它可以防止有人打算使用基類作爲實例時,功能中的類的錯誤使用,基類應該被設計爲基礎,並且就是這樣。

對於某些類型的屬性,iI會建議使用這種方法,而不是對不同類型的實體共享相同屬性的基類,因此通過接口封裝這些屬性,並且只爲實現了知道聯繫信息的實體細節:

public interface IContactDetails 
{ 
    string Email { get; } 
    string Address { get; } 
} 
相關問題