2010-03-06 36 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; } 
} 

家长可以为空当你不知道父。 当你没有孩子时,孩子可以是空的或空的。 由于每个孩子都是一个人,它可以有一个父母或自己的孩子。

这个设计本身是很好的,直到你提供更详细的用例场景,了解它将如何使用或持续使用。