2011-07-11 10 views
3

私は、同様のプロパティ(例:Student、Teacher、Contact、User)を持つ多数のサブクラス(Personの)を必要とするアプリケーションを構築しています。プロパティにはかなりの重なりがありますが、多くの違いもあります。たとえば、PersonはStudent、Contact、Userのいずれかです。ここでは(分かりやすくするために制限)の例である:複数の類似したクラスのための良いデザインと考えられるもの

Person 
    FirstName 
    LastName 
    DOB 
    CurrentAge 

Student <- Person 
    StudentId 
    Average 
    Email 
    Phone 

Contact <- Person 
    Email 
    Phone 
    Address 

User <- Person 
    Email 
    UserName 
    DOB 
    CurrentAge 

私はコードを書く避けるために複数回を希望 - 例:などのメール検証コード、年齢を計算するのに必要なコードを、また、我々は、おそらく追加する必要があります後でクラスが追加され、同様のオーバーラップと違いがあります。

これを処理するには、どのような良い設計が考えられますか、それともどのような設計パターンがこれをカバーしていますか?

デザインパターンの私の基本的な理解から、デコレータは正しくないようです。私は動作を追加していません。コンポジットは再帰的ではありません。私はまた、これに理想的なパターンがないかもしれないことを理解していますが、それは非常に共通の要件のようです。

重要な場合、これは主にASP.NET/C#/ VB.NETで使用されます。

その他の質問には、2つの同様のクラス/オブジェクト(一般にサブクラス化)の回答がありますが、任意の数の類似したクラスについては何も見つかりませんでした。

関連するデータベース設計に関する提案も歓迎します。

+0

私は正しいとして2つの答えを受け入れるように見えることはできませんが、私の最終的な解決策は、データを格納し、データそのものの検証処理するために、ポールSonierから組成の提案をincoroporateなり、そしてからインターフェイスと役割の提案重複するプロパティ(複数のインターフェースを実装する)とロジック(IContactに少なくとも1つの連絡方法が指定されていることを検証する役割)を処理する@Don Robby。 –

答えて

4

Compositionを使用して、複数の異なるクラスの機能を組み合わせたいとします。あなたが本当に探しているのは、ニーズに基づいてさまざまなレベルの機能を定義できるように、オブジェクト階層を設計する方法です。これを行う最も簡単な方法は、機能を定義するためにCompositionを使用することです。

たとえば、あなたの例では、Personには電子メールアドレスは必要ありません。しかし、Contactがあり、Userがあります。どちらもPersonから継承しています。これを処理する方法は、Emailクラスを持つことです。次に、ContactクラスとUserクラスが持つことができるクラスです。そのクラスは検証などを管理できますEmailPersonにアタッチしたい場合は、Personを継承し、継承したPersonを継承するクラスを持ちます(より良い名前を選んでください)。 Emailクラス。そのようにして、PersonWithEmailから継承するクラスはPerson機能とEmail機能を得るでしょう。しかし、このタイプのアプローチの問題は、継承階層で直接コンポジションを定義していることです。これは望ましくないかもしれません。ダイレクトコンポジションアプローチは簡単です。

+1

ありがとうPaul! 「直接合成アプローチ」とはどういう意味ですか?あなたはプロパティタイプのクラスを自分で作ることを指していますか?もしそうなら、それは私が電子メール、住所、電話などでやっていることです。私が理解できないことは、異なるルールを持つ方法です(例:連絡先には電話、住所、電子メールのいずれかが必要ですが、学生は電子メールと電話が必要です)。何かヒント? –

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クラスにRole個のオブジェクトを含むのフィールドを入れることで、複数の役割を持つことができます。

+0

ありがとうございました。あなたは、これが電子メールのような重複するプロパティでどのように機能するかの例を挙げることができますか?私は、電子メールを必要とする多くの役割を担っていたとしても、1つの電子メールアドレスだけを保存したいと考えています。 –

0

クラスが従属関係にあると言うことができる場合には、サブクラス化を使用してください。Tiger ""です。そうでなければ、新しい動作を追加するような大きな階層の階層を維持することができません。

また、基底クラスをabstractとすることを忘れないでください。インスタンスで基底クラスを使用することを意図した人物、基底クラスとして基底クラスを設計する必要がある場合、機能のクラスの不正使用を防止します。

いくつかの種類のプロパティでは、異なる種類のエンティティに対して同じプロパティを共有する基本クラスの代わりにこのようなアプローチを使用することを提案します。そのようなプロパティをインターフェイスでカプセル化し、連絡先情報を認識するエンティティ詳細:

public interface IContactDetails 
{ 
    string Email { get; } 
    string Address { get; } 
} 
関連する問題