2010-03-06 17 views
9

Ich habe eine Person-Klasse und zwei geerbte Klassen mit Namen Parent und Child. Ein Elternteil kann n Kind (e) haben und ein Kind kann n Elternteil (e) haben.So verweisen Sie auf Objekte in Klassen

Was ist der beste Weg in OOD, einen Verweis zwischen einem Elternteil und einem Kind zu erstellen.

Soll ich in jeder Klasse eine Liste erstellen, die auf das verbundene Eltern/Kind verweist, oder gibt es einen besseren Weg?

Antwort

11

Große Frage.Reine Viele-zu-Viele-Beziehungen sind tatsächlich ziemlich selten, und es hilft normalerweise, ein Zwischenobjekt einzuführen, um die Beziehung selbst zu modellieren. Dies wird von unschätzbarem Wert, wenn (wenn!) Verwenden Fälle entstehen, die die Erfassung von Eigenschaften erfordern in Bezug auf die Beziehung (zum Beispiel, ob das Kind/Eltern-Beziehung ist natürlich, Surrogat, angenommen, usw.).

So, zusätzlich zu der Person, Eltern und Kind Einheiten, die Sie bereits identifiziert haben, lassen Sie uns ein Objekt vorstellen ParentChildRelationship genannt. Eine Instanz ParentChildRelationship einen Verweis auf genau einem Elternteil hat und ein Kind, und sowohl die Eltern-Kind-Klassen werden eine Sammlung von diesen Unternehmen halten.

Es ist eine gute Idee, um dann die Sie Anwendungsfälle identifizieren müssen mit diesen Elementen arbeiten können, und fügen Sie Methoden geeignete Helfer die interObjektReferenzen zu halten. Im folgenden Beispiel habe ich gerade eine öffentliche AddChild-Methode zum übergeordneten Objekt hinzugefügt.

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

Das Bild fehlt ... Können Sie bitte das Bild auf Imgur anstatt, einen Verweis auf den Dropbox Link posten? – Sometowngeek

1

Wenn Sie die Richtung der Verbindung beschränken können, nur One Way zu gehen, sparen Sie sich eine Menge Ärger (aber das ist nicht immer möglich).

One-Way-Beziehung:

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

Wenn Sie auch den Verein geht in die andere Richtung haben wollen, können Sie dies auch tun können:

Allerdings haben Sie jetzt einen Kreis Referenz, die Sie pflegen müssen, und obwohl es möglich ist, ist es nicht besonders produktiv.

Sie können die Verknüpfung oft als eine einseitige Beziehung beibehalten, indem Sie die Kinder Ereignisse auslösen anstatt explizit auf ihre Eltern verweisen.

1

Ich könnte mir vorstellen, dass ein Kind auch ein Elternteil auf der ganzen Linie sein kann (wenn er Glück hat ... oder Pech, je nach Standpunkt), so würde ich mit etwas gehen wie:

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 
} 

Und du könntest es einfach so erweitern, wie du es magst, wenn neue Anforderungen kommen (vertrau mir das).

aktualisieren: in Ihrem Fall also, wenn Sie nur ein Kind Eltern und den anderen Weg zu haben um Sie so etwas wie tun würde:

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 
} 

Auf diese Weise, wenn Sie einen IHaveFriends haben wollen Schnittstelle, die Sie können (was den Implementierer dazu zwingt, eine Liste von IPersons als eine Eigenschaft namens Friends verfügbar zu machen). Wenn Sie es nicht brauchen, tun Sie es nicht, aber die Tatsache, dass Sie es einfach tun können, einfach eine Schnittstelle hinzufügen und alles andere gleich bleibt, bedeutet, dass Sie ein ziemlich anständiges erweiterbares Modell haben (nicht unbedingt das Beste, wissen Sie was ich meine).

+0

Acctually in meinem Beispiel das Kind wird nie einen Elternteil worden ist, wird es lange aus dem System geworfen vor diesem :-) – Zooking

+0

cool - aber das ist nur ein Beispiel, die Botschaft, die ich versucht bin zu vermitteln ist, dass ich noch Child-und Eltern-Klassen erstellen würde, die sie implementieren, dass IHaveParents und IHaveChildren (außer IPerson) für die Erweiterbarkeit. – JohnIdol

+0

Ok, aber in meinem Beispiel wäre es möglich, nur das Interface IHaveChildOrParent zu haben? Ich sage nicht, dass es nett wäre, sich nur zu fragen, ob es möglich wäre, die zwei zu teilen und ob es irgendwelche Vorteile gibt. – Zooking

1

Wie John Idol darauf hingewiesen hat, könnte ein Kind auf der ganzen Linie ein Elternteil werden. Mit anderen Worten: Machen Sie keine Eltern- und Kind-Unterklassen von Person.

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

Ob Sie konkrete Eltern- und Kinderklassen einführen möchten, hängt wirklich von der Art des zu entwickelnden Systems ab. Wenn es Genealogie/Stammbaum-Software ist, dann stimme ich Ihnen nur eine konkrete Person-Klasse wünschen würden. Aber wenn Sie Software entwickeln, um Kinderunterhalt/Sozialleistungen zu verfolgen, dann wären wahrscheinlich konkrete Klassen für Eltern und Kind erforderlich, da diese Entitäten ziemlich unterschiedliche Attribute hätten und die Tatsache, dass ein Kind schließlich selbst ein Elternteil werden könnte für das System irrelevant sein. –

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

Elternteil kann null sein, wenn Sie die Eltern nicht kennen. Kinder können null oder leer sein, wenn Sie keine Kinder haben. Da jedes Kind eine Person ist, kann es ein Elternteil oder seine eigenen Kinder haben.

Dieser Entwurf ist für sich in Ordnung, bis Sie detailliertere Anwendungsszenarien für die Verwendung oder die Verwendung bereitstellen.

Verwandte Themen