2012-07-03 11 views
8

Ich habe eine Kategorie/Datei Baumstruktur. Beide Kategorien und Dateien können Eltern haben, daher habe ich sie aus einer gemeinsamen Basisklasse mit einer Parent-Eigenschaft abgeleitet. Da alle Eltern offensichtlich immer Kategorien sind (Dateien können keine Eltern sein), scheint es sinnvoll zu sein, die Parent-Eigenschaft des Knotens zum CategoryNode-Typ zu machen.Ist es eine schlechte Form, auf einen abgeleiteten Typ in einem Basistyp zu verweisen?

Ist es eine schlechte Form für die Basisklasse, auf die abgeleitete Klasse zu verweisen? Wenn ja warum? Was ist eine bessere Möglichkeit, dies zu strukturieren, wenn ja?

class Node { 
    public CategoryNode Parent {get; set;} 
} 

class File : Node { 
    ... 
} 

class CategoryNode : Node { 
    ... 
} 
+0

AFAIU, beide erweitern die gleiche Basisklasse für die Freigabe von Eigenschaften, also warum nicht auf einzelne Klasse mit rekursiven Verweis auf sich selbst verwenden? mit zusätzlichen Eigenschaften, um sie zu unterscheiden. –

+0

ja das ist schlecht. Bewirkt eine zirkuläre Abhängigkeit. Base sollte nichts über Abgeleitet wissen. – Tilak

+0

@Furqan, der File-Knoten braucht nicht die zusätzlichen Sachen, die CategoryNode hat, wie Kinder, also glaube ich nicht, dass er von CategoryNode abgeleitet sein sollte. – Kelsie

Antwort

4

Wenn die Eigenschaft Parent ist eigentlich eine gemeinsame Eigenschaften aller Nachkommen und immer der Art CategoryNode, es ist kein Problem. Semantisch gesehen ist es korrekt und technisch ist es auch korrekt, sobald Sie in derselben Bibliothek bleiben (um zirkuläre Referenzen zu vermeiden).

Dies kann ein Problem sein, wenn Sie Code wie folgt schreiben:

// BAD CODE 
if(myProp is subclassA) 
{ ... 
} 
else if (myProp is syubclassB) 
{ ... 
} 

Dieser Code ist schlecht, weil Sie den Vorteil der Vererbung verlieren.

Auch im .NET Framework gibt es solche Konstrukte. Das erste Beispiel, das mir in den Sinn kommt, ist die -Eigenschaft.

XElement erbt XObject und XObject veröffentlicht eine Eigenschaft des Typs XElement. Genau wie Ihr Snippet.

1

Die Basisklasse sollte nicht wissen, wer davon abgeleitet wird.

Wenn Sie einen solchen Fall haben, wollen Sie wahrscheinlich keine Vererbung. Sie sollten nur eine Form der Kopplung verwenden.

Die Datei und CategoryNode sollte in Ihrem Fall ein Node-Mitglied enthalten.

+0

Ich kann dir nicht zustimmen. Was ist, wenn Parent immer ein CategoryNode ist? Es kann ein Problem sein in der Basisklasse gibt es Dinge wie 'if (myProp is subclassA) {...} sonst if (myProper ist syubclassB) {...}'. Solche Dinge sind schmutzig. Aber nicht die Probe die OP schlägt vor –

+0

Aber es ist nicht. Wir haben gerade gesehen, dass die übergeordnete Datei sein kann, die in keiner Weise CategoryNode zugeordnet ist. –

+0

das OP sagte, dass 'Dateien können nicht ein Elternteil sein ' –

1

Andere Optionen bestehen darin, die Klassenhierarchie zu ändern, um den CategoryNode zu einer Stammklasse (a) zu machen, oder den Eigenschaftstyp in Node (b) zu ändern.

Beide Möglichkeiten sind nicht gut: (a) Datei wird alle Funktionen haben, die CategoryNode hat, die es nicht benötigt. (b) Es wird den Objekttyp (der immer CategoryNode ist) ausblenden. Dies kann zu ungültigen Besetzungsfehlern an anderer Stelle in Ihrem Code führen. Zum Beispiel, wenn Sie vergessen, gibt es immer eine CategoryNode-Instanz.

In Anbetracht dessen glaube ich, dass der aktuelle Code in Ordnung ist.

7

Sie tun könnte ...

interface IParent { 
    ... 
} 

class Node { 
    public IParent Parent {get; set;} 
} 

class File : Node { 
    ... 
} 

class CategoryNode : Node, IParent { 
    ... 
} 

Auf diese Weise müssen Sie nicht auf ein abgeleitetes Objekt in der Basisklasse beziehen müssen, plus, Sie flexibler sind in dem, was ein Elternteil tatsächlich werden kann , falls Sie zu einem späteren Zeitpunkt weitere Objekttypen erhalten. Außerdem kann jede Funktionalität, die nur für ein Elternelement relevant ist, in dieser Schnittstelle deklariert werden.

+0

Vielleicht können Sie in der Schnittstelle hinzufügen:' IEnumerable ChildNodes'? –

+0

@Steve Dies ist eine Designfrage. Sicherlich ist das möglich, aber ich würde die Schnittstelle "IParent" nicht mehr nennen. Das OP wollte auf ein Elternobjekt und nicht auf eine (Liste von) Kindobjekt (en) verweisen. Für mich sieht es komisch aus, dass sowas als 'IEnumerable Children' deklariert ist, und persönlich würde ich die Schnittstelle in etwas passenderes umbenennen ... wenn Sie ein großes Projekt mit vielen Beispielen für diese Art von Benennungsstil haben bin auf dem Weg zur Hölle IMHO ... – takrl

+0

hast du recht ... das kann zu Verwirrung führen –

Verwandte Themen