2010-03-06 40 views
9

我有一個Person類和兩個名爲Parent和Child的繼承類。父母可以有n個孩子,孩子可以有n個父母。如何在類中交叉引用對象

在OOD中創建父母與子女之間的參考的最佳方式是什麼?

我應該在引用連接的父/子的每個類中創建一個List還是有更好的方法?

回答

11

偉大的問題。純多對多關係實際上非常罕見,通常有助於引入一箇中間對象來模擬關係本身。如果(當!)用例出現需要捕獲有關關係的屬性(例如,孩子/父母關係是否是自然的,代理的,收養的等等),這將證明是非常寶貴的。

因此,除了您已經識別的Person,Parent和Child實體之外,我們還介紹一個名爲ParentChildRelationship的對象。 ParentChildRelationship的一個實例將只有一個Parent和One Child的引用,並且Parent和Child兩個類都將擁有這些實體的集合。

這是一個好主意,然後確定用於處理這些實體的用例,並添加適當的幫助器方法以維護對象間引用。 在下面的示例中,我剛選擇向父級添加公共AddChild方法。

alt text

public abstract class Person 
{ 
} 

public class Parent : Person 
{ 
    private HashSet<ParentChildRelationship> _children = 
     new HashSet<ParentChildRelationship>(); 

    public virtual IEnumerable<ParentChildRelationship> Children 
    { 
     get { return this._children; } 
    } 

    public virtual void AddChild(Child child, RelationshipKind relationshipKind) 
    { 
     var relationship = new ParentChildRelationship() 
     { 
      Parent = this, 
      Child = child, 
      RelationshipKind = relationshipKind 
     }; 

     this._children.Add(relationship); 
     child.AddParent(relationship); 
    } 
} 

public class Child : Person 
{ 
    private HashSet<ParentChildRelationship> _parents = 
     new HashSet<ParentChildRelationship>(); 

    public virtual IEnumerable<ParentChildRelationship> Parents 
    { 
     get { return this._parents; } 
    } 

    internal virtual void AddParent(ParentChildRelationship relationship) 
    { 
     this._parents.Add(relationship); 
    } 
} 

public class ParentChildRelationship 
{ 
    public virtual Parent Parent { get; protected internal set; } 

    public virtual Child Child { get; protected internal set; } 

    public virtual RelationshipKind RelationshipKind { get; set; } 
} 

public enum RelationshipKind 
{ 
    Unknown, 
    Natural, 
    Adoptive, 
    Surrogate, 
    StepParent 
} 
+0

圖像丟失了......你可以發佈imgur上的圖像,而不是參考Dropbox鏈接? – Sometowngeek 2017-06-20 18:15:17

1

如果您可以限制關聯的方向,只需要單向,您將爲自己節省很多麻煩(但這並非總是可行)。

單向關係:

public class Parent : Person 
{ 
    public IEnumerable<Person> Children { get; } 
} 

如果你想擁有聯想去另一個方向,以及,你也可以這樣做:

但是,現在你有一個圓形請參考您需要維護的信息,儘管可能,但並不是特別有效。

通過讓孩子引發活動而不是顯式引用其父母,您可以經常保持該關聯爲單向關係。

1

我會想象,一個孩子也可以是父向下行(如果他得到幸運......還是不幸,這取決於觀點),所以我會喜歡的東西去:

IPerson 
{ 
    string Name {get; set;} 
    string LastName {get; set;} 
    // whatever else - such as sizeOfShoe, dob, etc 
} 

IHaveParents 
{ 
    // might wanna limit this to a fixed size 
    List<IPerson> Parents {get; set;} 
} 

IHaveChildren 
{ 
    List<IPerson> Children {get; set;} 
} 

IHaveSpouse 
{ 
    IPerson Spouse {get; set;} 
} 

public class DudeWithParentsAndChildren : IPerson, IHaveParents, IHaveChildren, IHaveSpouse 
{  
    public void AskMoneyToParents(){throw new Exception("Implement me!");} 
    public void SlapChildren(){} 
    private void CheatOnSpouse(){} 
    // some other stuff that such a dude can do i.e. GoBowling 
} 

當新的需求出現時,您可以輕鬆地以任何方式擴展它(相信我他們會這麼做)。

更新: 所以你的情況,如果你只想要一個孩子有父母和周圍的其他方法,你會做這樣的事情:如果你想有一個IHaveFriends

public class Child : IPerson, IHaveParents 
{  
    public void AskMoneyToParents(){throw new Exception("Implement me!");} 
} 

public class Parent : IPerson, IHaveChildren, IHaveSpouse 
{  
    public void SlapChildren(){} 
    private void CheatOnSpouse(){} 
    // some other stuff that such a dude can do i.e. GoBowling 
} 

這樣接口你可以(這基本上迫使實現者公開IPersons列表作爲名爲Friends的屬性)。如果你不需要它,不要這樣做,但事實上,你可以輕鬆地做到這一點,只是添加一個接口和其他一切都保持不變,這意味着你有一個相當不錯的可擴展模型(不一定是最好的,你知道我的意思是)。

+0

Acctually在我的例子中,孩子將永遠不會成爲父母,這是拋出了系統的長時間,:-)前 – Zooking 2010-03-06 16:57:39

+0

酷 - 但是這只是一個例子,我想消息爲了解決這個問題,我仍然會創建Child和Parent類,使它們分別實現IHaveParents和IHaveChildren(除IPerson之外)的可擴展性。 – JohnIdol 2010-03-06 17:02:21

+0

好的,但在我的例子中可能只有接口IHaveChildOrParent?我並不是說只是想知道是否有可能分享這兩種產品,以及是否有任何優勢。 – Zooking 2010-03-06 17:16:59

1

正如JohnIdol指出的那樣,一個小孩可能會成爲父母。換句話說,不要讓Person的Parent和Child子類。

class Person 
{ 
    readonly List<Person> _children = new List<Person>(), 
         _parents = new List<Person>(); 

    public IEnumerable<Person> Children 
    { 
     get { return _children.AsReadOnly(); } 
    } 

    public IEnumerable<Person> Parents 
    { 
     get { return _parents.AsReadOnly(); } 
    } 

    public void AddChild(Person child) 
    { 
     _children.Add(child); 
     child._parents.Add(this); 
    } 

    public void AddParent(Person parent) 
    { 
     _parents.Add(parent); 
     parent._children.Add(this); 
    } 

    /* And so on... */ 
} 
+0

是否選擇引入具體的父類和子類實際上取決於正在開發的系統的性質。 如果是族譜/家族樹軟件,那麼我同意你只想要一個具體的Person類。 但是,如果您正在開發追蹤兒童撫養費/撫卹金的軟件,那麼可能需要父母和孩子的具體類別,因爲這些實體具有完全不同的屬性,以及兒童最終可能成爲父母的事實會與系統無關。 – 2010-03-06 21:05:22

2
public class Person 
{ 
    Person Parent { get;set; } 
    IList<Person> Children { get;set; } 
} 

家長可以爲空當你不知道父。 當你沒有孩子時,孩子可以是空的或空的。 由於每個孩子都是一個人,它可以有一個父母或自己的孩子。

這個設計本身是很好的,直到你提供更詳細的用例場景,瞭解它將如何使用或持續使用。