如何在类中交叉引用对象

我有一个Person类和两个名为Parent和Child的inheritance类。 父母可以有n个孩子,孩子可以有n个父母。

OOD在父和子之间创建引用的最佳方法是什么。

我应该在引用连接的父/子的每个类中创建一个List,还是有更好的方法?

好问题。 纯粹的多对多关系实际上非常罕见,它通常有助于引入一个中间对象来模拟关系本身。 如果(当!)用例出现需要捕获关于关系的属性(例如,子/父关系是自然的,代理的,收养的等),这将是非常宝贵的。

因此,除了您已经识别的Person,Parent和Child实体之外,我们还要介绍一个名为ParentChildRelationship的对象。 ParentChildRelationship的实例将只引用一个Parent和One Child,Parent和Child类都将包含这些实体的集合。

然后,最好确定使用这些实体的用例,并添加适当的辅助方法来维护对象间引用。 在下面的示例中,我刚刚选择将公共AddChild方法添加到父级。

替代文字

public abstract class Person { } public class Parent : Person { private HashSet _children = new HashSet(); public virtual IEnumerable 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 _parents = new HashSet(); public virtual IEnumerable 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 } 
 public class Person { Person Parent { get;set; } IList Children { get;set; } } 

如果您不知道父级,则父级可以为null。 如果您没有孩子,孩子可以为空或空。 由于每个孩子都是一个人,它可以有一个父母或自己的孩子。

在您提供有关如何使用或持久化的更详细的用例场景之前,此设计本身就可以了。

如果你可以限制关联的方向只走一条路 ,你将省去很多麻烦(但这并不总是可行的)。

单向关系:

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

如果你想让关联走向另一个方向,你也可以这样做:

 public class Child : Person { public Parent Parent { get; } } 

但是,现在您需要维护一个循环引用,尽管可能,但它并不是特别有效。

您通常可以通过让孩子们举起事件而不是明确地引用他们的父母来将关联保持为单向关系。

正如JohnIdol指出的那样,一个孩子可能会成为父母。 换句话说,不要制作Person的Parent和Child子类。

 class Person { readonly List _children = new List(), _parents = new List(); public IEnumerable Children { get { return _children.AsReadOnly(); } } public IEnumerable 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... */ } 

我想象一个孩子也可以成为一个父母(如果他运气好……或者不幸的话,取决于观点)所以我会选择以下内容:

 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 Parents {get; set;} } IHaveChildren { List 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 ie GoBowling } 

当新的需求出现时,您可以轻松地以任何方式扩展它(相信我会)。

更新 :所以在你的情况下,如果你只想要一个孩子有父母,反过来你做的事情如下:

 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 ie GoBowling } 

这样,如果你想拥有一个IHaveFriends接口,你可以(这基本上迫使实现者将一个IPersons列表公开为名为Friends的属性)。 如果你不需要它,那就不要这样做,但事实上你可以轻松地添加一个接口而其他一切都保持不变意味着你有一个相当不错的可扩展模型(不一定是最好的,你知道我的意思是说)。