Warum nicht von List & lt; T & gt;
Bei der Planung meine Programme, die ich starten oft mit einer Kette von Gedanken wie:
Einer Fußball-Mannschaft ist nur eine Liste der Fußball-Spieler. Also, ich soll es mit:
var football_team = new List<FootballPlayer>();
Die Bestellung von dieser Liste repräsentieren die Reihenfolge, in der die Spieler aufgeführt sind, die in den Dienstplan.
Aber ich merke später, dass die teams haben auch andere Eigenschaften, neben der reinen Liste der Spieler, die festgehalten werden müssen. Zum Beispiel, die laufende Summe erzielt in dieser Saison, das aktuelle budget, die uniform-Farben, ein string
für den Namen der Mannschaft, etc..
Also dann denke ich:
Okay, ein Fußball-team ist ebenso wie eine Liste von Spielern, sondern zusätzlich, es hat einen Namen (eine
string
) und eine laufende Summe der scores (einint
). .NET nicht eine Klasse für die Speicherung von Fußball-teams, also werde ich meine eigene Klasse. Die meisten ähnlichen und relevanten vorhandenen StrukturList<FootballPlayer>
, so werde ich von Ihr Erben:class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }
Aber es stellt sich heraus, dass eine Richtlinie sagt, man sollte nicht die Erben von List<T>
. Ich bin gründlich verwirrt durch diese Richtlinie in zweifacher Hinsicht.
Warum nicht?
Offenbar List
ist irgendwie für die Leistung optimiert. Wie so? Was performance-Probleme werde ich veranlassen, wenn ich verlängern List
? Was genau wird kaputt?
Einem anderen Grund, den ich gesehen habe, ist, dass List
von Microsoft bereitgestellt wird, und ich habe keine Kontrolle über Sie, so Ich kann es nicht ändern später, nachdem man eine "public API". Aber ich kämpfen, um das zu verstehen. Was ist eine öffentliche API und warum sollte mich das interessieren? Wenn mein Aktuelles Projekt nicht und ist wahrscheinlich nicht immer haben diese öffentliche API, die kann ich ignorieren diese Richtlinie? Wenn ich Erben von List
und es stellt sich heraus, ich brauche eine öffentliche API, welche Schwierigkeiten habe ich?
Warum ist es auch egal? Eine Liste ist eine Liste. Was könnte sich ändern? Was könnte ich vielleicht ändern wollen?
Und schließlich, wenn Microsoft wollte mich nicht Erben aus List
, warum haben Sie nicht machen die Klasse sealed
?
Was soll ich verwenden?
Offenbar für eine benutzerdefinierte Sammlungen, die Microsoft bereitgestellt hat, eine Collection
- Klasse, die erweitert werden soll, anstatt List
. Aber diese Klasse ist sehr nüchtern, und nicht haben viele nützliche Dinge, wie AddRange
, zum Beispiel. jvitor83 Antwort bietet eine Leistung Begründung für die jeweilige Methode, aber wie ist ein langsamer AddRange
nicht besser als gar keine AddRange
?
Erben von Collection
ist viel mehr Arbeit, als Erben von List
, und ich sehe keinen Vorteil. Sicherlich Microsoft würde nicht sagen Sie mir, um zusätzliche Arbeit zu tun, ohne Grund, so kann ich nicht helfen Gefühl, wie ich bin irgendwie Missverständnis etwas, und Erben Collection
ist eigentlich nicht die richtige Lösung für mein problem.
Ich gesehen habe Vorschläge, wie die Umsetzung IList
. Nur kein. Dies ist Dutzende von Zeilen boilerplate-code, die Gewinne mir nichts.
Schließlich, einige schlagen vor, das einwickeln der List
in etwas:
class FootballTeam
{
public List<FootballPlayer> Players;
}
Gibt es zwei Probleme:
- Macht es mein code unnötig ausführlich. Ich muss jetzt anrufen
my_team.Players.Count
statt nurmy_team.Count
. Zum Glück, mit C# kann ich definieren, Indexer, um die Indizierung transparent, und uns alle die Methoden des internenList
... Aber das ist eine ganze Menge code! Was bekomme ich für alle, dass die Arbeit? - Einfach keinen Sinn. Eine Fußball-Mannschaft nicht "haben" eine Liste der Spieler. Es ist die Liste der Spieler. Sagen Sie nicht: "John McFootballer hat sich SomeTeam Spieler". Sie sagen: "John hat sich SomeTeam". Sie don T fügen Sie einen Brief an "einen string s Zeichen", fügen Sie einen Buchstaben in einen string. Sie don ' T fügen Sie ein Buch zu einer Bibliothek, die Bücher, die Sie hinzufügen, ein Buch zu einer Bibliothek.
Merke ich, dass was passiert "unter der Haube" kann gesagt werden, "hinzufügen von X zu Y die interne Liste", aber dies scheint wie eine sehr counter-intuitive Art und Weise des Denkens über die Welt.
Meine Frage (zusammengefasst)
Was ist die richtige C# Möglichkeit der Darstellung einer Datenstruktur, die "logisch" ist (das heißt, "den menschlichen Geist") ist nur ein list
von things
mit ein paar Glocken und Pfeifen?
Erbt von List<T>
immer inakzeptabel? Wann ist es akzeptabel? Warum/warum nicht? Was muss ein Programmierer betrachten, bei der Entscheidung, ob Erben von List<T>
oder nicht?
string
muss, um alles ein object
tun können, und mehr. InformationsquelleAutor der Frage Superbest | 2014-02-11
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es einige gute Antworten hier. Ich würde hinzufügen, um Sie, die folgenden Punkte.
Bitten alle zehn nicht-computer-Programmierer, Leute, die vertraut sind mit der Existenz des Fußballs, füllen Sie die leeren:
Haben jemand sagen Sie "Liste der Fußball-Spieler mit ein paar Glocken und Pfeifen", oder haben Sie alle sagen "Sport-team" oder "Verein" oder "Organisation"? Ihre Vorstellung, dass eine Fußball-Mannschaft eine Besondere Art von Liste der Spieler ist in Ihrem menschlichen Geist und den menschlichen Geist allein.
List<T>
ist ein Mechanismus. Fußball-team ist eine business-Objekt -- das heißt, ein Objekt, das bedeutet das Konzept, dass in der business domain des Programms. Don ' T mix! Ein Fußball-team ist eine Art team; es hat eine Dienstplan, Dienstplan ist eine Liste der Spieler, die. Ein Dienstplan ist kein Besondere Art von Liste der Spieler. Ein Dienstplan ist eine Liste von Spielern. So stellen Sie eine Eigenschaft namensRoster
ist einList<Player>
. Und machen esReadOnlyList<Player>
während Sie gerade dabei sind, es sei denn, Sie glauben, dass jeder, kennt ein Fußball-team bekommt zu löschen-Spieler aus dem Dienstplan.Nicht akzeptabel für wen? Mich? Nein.
Wenn Sie bauen einen Mechanismus, der erweitert die
List<T>
Mechanismus.Bin ich bauen ein Mechanismus oder eine business-Objekt?
Sie verbrachte mehr Zeit die Eingabe Ihrer Frage, die Sie sich genommen haben Sie zu schreiben forwarding-Methoden für die jeweiligen Mitglieder der
List<T>
fünfzig mal vorbei. Du hast eindeutig keine Angst vor Ausführlichkeit, und wir reden über eine sehr kleine Menge von Programmcode hier; dies ist ein paar Minuten Arbeit.UPDATE
Gab ich es ein paar mehr Gedanken und es ist ein weiterer Grund, nicht Modell, ein Fußball-team als eine Liste von Spielern. Es wäre In der Tat eine schlechte Idee, Modell, ein Fußball-team als mit eine Liste von Spielern zu. Das problem mit team/mit einer Liste der Spieler ist, dass was du hast ist ein snapshot des Teams an einen moment in der Zeit. Ich weiß nicht, was der business case ist für diese Klasse, aber wenn ich hatte eine Klasse, die vertreten, ein Fußball-team ich würde mir wünschen, bitten, es Fragen wie "wie viele Seahawks-Spieler verpasste Spiele aufgrund einer Verletzung zwischen 2003 und 2013?" oder "Was Denver Spieler, der zuvor für ein anderes team gespielt hatte, das größte Jahr-über-Jahr Zunahme yards ran?" oder "Habe die Piggers den ganzen Weg gehen in diesem Jahr?"
Ist, ein Fußball-team scheint mir gut zu sein modelliert als eine Sammlung von historischen Fakten wie wenn ein Spieler rekrutiert wurde, verletzt, Rentner usw. Offensichtlich ist die aktuelle Spieler-Kader ist eine wichtige Tatsache, dass sollte wohl front-und-center, aber es können auch andere interessante Dinge, die Sie tun möchten, mit diesem Objekt, Bedarf es einer historischen Perspektive.
InformationsquelleAutor der Antwort Eric Lippert
Das ist der richtige Weg. "Unnötig wortreich" ist ein schlechter Weg, dies zu betrachten. Es hat eine klare Bedeutung, wenn Sie schreiben
my_team.Players.Count
. Sie zählen möchten, die Spieler...bedeutet nichts. Graf was?
Ein team ist nicht eine Liste, die aus mehr als nur eine Liste von Spielern. Ein team besitzt Spieler, also Spieler, die ein Teil davon sein sollte (ein Mitglied).
Wenn Sie wirklich besorgt, dass übermäßig verbose, können Sie immer machen Eigenschaften aus dem team:
..das wird:
Dieser hat eine Bedeutung, jetzt und hält sich an Das Gesetz Von Demeter.
Sollten Sie auch prüfen, die Einhaltung der Composite-reuse-Prinzip. Durch Erben von
List<T>
, du sagst ein team ist ein Liste der Spieler und setzen unnötig Methoden aus. Dies ist falsch, - wie Sie erklärte, ein team ist mehr als eine Liste der Spieler: hat einen Namen, Führungskräfte, Vorstandsmitglieder, Trainer, medizinisches Personal, Gehalt Kappen, etc. Durch Ihre team-Klasse enthält eine Liste von Spielern, sagst du: "Ein team hat eine Liste der Spieler, aber es können auch noch andere Dinge.InformationsquelleAutor der Antwort Simon Whitehead
Wow, dein post hat eine ganze Reihe von Fragen und Punkten. Die meisten der Argumentation, die Sie von Microsoft erhalten, ist genau auf dem Punkt. Beginnen wir mit alles über
List<T>
List<T>
ist stark optimiert. Die eigentliche Verwendung ist der Einsatz als private member eines Objekts.class MyList<T, TX> : List<CustomObject<T, Something<TX>> { ... }
. Jetzt ist es so einfach wie zu tunvar list = new MyList<int, string>();
.IList<T>
wenn Sie alle Verbraucher haben eine indizierte Liste. Dies können Sie ändern Sie die Implementierung innerhalb einer Klasse später auf.Collection<T>
sehr generisch, weil es sich um ein generisches Konzept... der name sagt alles; es ist nur eine Sammlung. Es sind präziser Versionen wieSortedCollection<T>
,ObservableCollection<T>
,ReadOnlyCollection<T>
usw. jeder der die UmsetzungIList<T>
aber nichtList<T>
.Collection<T>
ermöglicht für die Mitglieder (d.h. Hinzufügen, Entfernen, etc.) außer Kraft gesetzt werden, weil Sie virtuell sind.List<T>
nicht.Wenn ich das schreiben würde die Klasse wohl Aussehen so:
InformationsquelleAutor der Antwort m-y
Vorherigen code bedeutet: ein paar Jungs aus der Straße Fußball zu spielen, und Sie haben zufällig einen Namen. So etwas wie:
Sowieso, dieser code (in meiner Antwort)
Bedeutet: dies ist ein football-team, das management, die Spieler, admins, etc. So etwas wie:
Dies ist, wie ist Ihre Logik, dargestellt in Bildern...
InformationsquelleAutor der Antwort Nean Der Thal
Dies ist ein klassisches Beispiel von Zusammensetzung vs Vererbung.
In diesem konkreten Fall:
Ist das team eine Liste von Spielern mit zusätzlichen Verhalten
oder
Ist das team ein Objekt seiner eigenen, die geschieht, um eine Liste der Spieler.
Durch die Ausweitung der Liste, die Sie begrenzen sich selbst in eine Anzahl von Möglichkeiten:
Können Sie nicht beschränken Sie den Zugriff (für Beispiel, stoppen Menschen ändern Dienstplan). Erhalten Sie die Liste der Methoden, ob Sie brauchen/wollen oder nicht.
Was passiert, wenn Sie haben wollen Listen andere Dinge auch. Zum Beispiel, teams haben Trainer, Manager, fans, Ausrüstung, etc. Einige von denen könnte gut sein, Listen in Ihrem eigenen Recht.
Begrenzen Sie Ihre Optionen für die Vererbung. Zum Beispiel möchten Sie möglicherweise erstellen Sie eine generische Team Objekt -, und dann haben BaseballTeam, FootballTeam, etc. Erben, die. Erben aus der Liste müssen Sie die Vererbung vom Team, aber das bedeutet dann, dass alle die verschiedenen Arten von team gezwungen sind, die gleiche Implementierung der Dienstplan.
Zusammensetzung - einschließlich ein Objekt geben, das Verhalten, das Sie wollen, in Ihrem Objekt.
Vererbung - Ihr Objekt wird zu einer Instanz des Objekts, das Verhalten, das Sie möchten.
Beide haben Ihren nutzen, aber das ist ein klarer Fall, wo die Komposition ist vorzuziehen.
InformationsquelleAutor der Antwort Tim B
Wie jeder darauf hingewiesen hat, ein team von Spielern ist nicht eine Liste von Spielern. Dieser Fehler wird von vielen Menschen überall, vielleicht auf verschiedenen Ebenen der Kompetenz. Oft ist das problem ist subtil und manchmal sehr grob, wie in diesem Fall. Solche designs sind schlecht, weil diese gegen die Liskov-Substitution-Prinzip. Das internet hat viele gute Artikel, die erklären, dieses Konzept z.B., http://en.wikipedia.org/wiki/Liskov_substitution_principle
Zusammenfassend gibt es zwei Regeln zu erhalten, die in einer Eltern/Kind-Beziehung zwischen den Klassen:
In anderen Worten, ein Elternteil ist eine notwendige definition eines Kindes, und ein Kind ist eine ausreichende definition eines Elternteils.
Hier ist eine Art zu denken, durch Lösung und gelten die oben genannten Grundsatz, dass helfen sollte man es vermeiden solche Fehler. Man sollte testen, diejenigen, die Hypothese, indem Sie überprüfen, ob alle Operationen, die von einer übergeordneten Klasse gelten für die abgeleitete Klasse sowohl strukturell als auch semantisch.
Wie Sie sehen, wird nur die erste Eigenschaft einer Liste ist für ein team. Damit ein team ist nicht eine Liste. Eine Liste wäre eine Implementierung detail, wie du dein team verwalten, so sollte es nur verwendet werden, um speichern Sie die Spieler-Objekte und manipuliert werden mit Methoden der Team-Klasse.
An dieser Stelle möchte ich anmerken, dass ein Team der Klasse sollte meiner Meinung nach auch nicht implementiert werden unter Verwendung einer Liste; es sollte umgesetzt werden und mit Hilfe einer Datenstruktur (HashSet, zum Beispiel) in den meisten Fällen.
InformationsquelleAutor der Antwort Satyan Raina
Was ist, wenn die
FootballTeam
hat eine Reserven-team zusammen mit den wichtigsten team?Wie würden Sie das Modell, das mit?
Die Beziehung ist eindeutig hat eine und nicht ist ein.
oder
RetiredPlayers
?Als eine Regel von Daumen, wenn Sie jemals wollen, um zu Erben aus einer Sammlung, name der Klasse
SomethingCollection
.Macht Ihr
SomethingCollection
semantisch Sinn machen? Tun Sie dies nur, wenn Ihr Typ ist ein Sammlung vonSomething
.Im Fall von
FootballTeam
es klingt nicht richtig. EinTeam
ist mehr als einCollection
. EinTeam
haben kann, coaches, Trainer, etc, da die anderen Antworten haben darauf hingewiesen.FootballCollection
klingt wie eine Sammlung von Fußbälle oder vielleicht eine Sammlung von Fußball-Utensilien.TeamCollection
eine Auflistung von teams.FootballPlayerCollection
klingt wie eine Auflistung der Spieler, welche würden Sie einen gültigen Namen für eine Klasse, die erbt vonList<FootballPlayer>
wenn Sie wirklich wollte, das zu tun.Wirklich
List<FootballPlayer>
ist eine ganz gute Art zu behandeln. VielleichtIList<FootballPlayer>
wenn Sie die Rückkehr aus einer Methode.Zusammenfassend
Fragen Sie sich
Ist
X
eineY
? oder HatX
eineY
?Tun meiner Klasse Namen bedeuten, was Sie sind?
InformationsquelleAutor der Antwort Sam Leach
Erste von allen, es hat zu tun mit usability. Wenn Sie die Vererbung verwenden, die
Team
Klasse aussetzen Verhalten (Methoden), die sind rein für Objekt-manipulation. Zum BeispielAsReadOnly()
oderCopyTo(obj)
Methoden keinen Sinn machen, für das team-Objekt. Statt derAddRange(items)
Methode würden Sie wahrscheinlich wollen eine mehr beschreibendeAddPlayers(players)
Methode.Wenn Sie möchten, verwenden Sie LINQ, die Implementierung einer generischen Schnittstelle
ICollection<T>
oderIEnumerable<T>
mehr Sinn machen würde.Wie bereits erwähnt, die Zusammensetzung ist der richtige Weg, um darüber zu gehen. Nur implementieren, die eine Liste der Spieler, die wie eine private variable.
InformationsquelleAutor der Antwort Dmitry S.
Design - > Umsetzung
Welche Methoden und Eigenschaften, die Sie setzen ist eine design-Entscheidung. Was Basisklasse Erben Sie von ist eine Implementierung detail. Ich fühle es sich lohnt, einen Schritt zurück zu den ehemaligen.
Ein Objekt ist eine Sammlung von Daten und Verhalten.
Damit Ihre ersten Fragen sollte sein:
Bedenken, dass die Vererbung impliziert eine "isa" (ist eine) Beziehung, in der Erwägung, dass die Zusammensetzung impliziert eine "hat ein" (hasa) Beziehung. Wählen Sie die richtige für Ihre situation aus Ihrer Sicht, unter Berücksichtigung, wo die Dinge gehen könnte, wie Sie Ihre Anwendung entwickelt.
Berücksichtigen, denken in Schnittstellen, bevor Sie denken in Beton-Arten, wie einige Leute finden es einfacher, um Ihr Gehirn in den "design-Modus" Weg.
Dies ist nicht etwas, das jeder tut, bewusst auf dieser Ebene von Tag zu Tag Codierung. Aber wenn Sie über diese Art von Thema, du trittst in design-Gewässern. Es zu wissen kann befreiend sein.
Betrachten Design Besonderheiten
Werfen Sie einen Blick auf List<T> und IList<T> auf MSDN oder Visual Studio. Sehen Sie, welche Methoden und Eigenschaften, die Sie setzen. Diese Methoden alle etwas Aussehen jemand tun würde, um ein FootballTeam aus Ihrer Sicht?
Tut footballTeam.Reverse() Sinn? Tut footballTeam.ConvertAll<TOutput>() wie etwas Aussehen, was Sie wollen?
Dies ist nicht eine Fangfrage; die Antwort könnte wirklich sein "ja". Wenn Sie implementieren/inherit List<Spieler> oder IList<Spieler>, du steckst mit Ihnen, wenn das ist ideal für Ihr Modell, es zu tun.
Wenn Sie sich entscheiden, ja, das macht Sinn, und Sie wollen Ihr Objekt behandelt werden als eine Sammlung/Liste der Spieler (das Verhalten), und Sie wollen deshalb die ICollection implementieren oder IList, mit allen Mitteln tun. Notionally:
Wenn Sie möchten, dass Ihr Objekt enthalten eine Sammlung/Liste der Spieler (- Daten), und Sie wollen deshalb die Sammlung oder Liste, um eine Eigenschaft oder-Mitglied, mit allen Mitteln tun. Notionally:
Könnte man glauben, dass Sie wollen, dass die Leute in der Lage sein, um nur die aufzuzählen, die Spieler, anstatt Sie zählen, um Sie hinzuzufügen oder Sie zu entfernen. IEnumerable<Player> ist eine durchaus Valide option zu prüfen.
Könnte man glauben, dass keines dieser interfaces sind nützlich in Ihrem Modell überhaupt. Dies ist weniger wahrscheinlich (IEnumerable<T> ist in vielen Situationen nützlich) aber es ist immer noch möglich.
Jemand, der versucht, Ihnen zu sagen, dass man von diesen ist es grundsätzlich und endgültig die falsch in jedem Fall ist falsch. Wer versucht, Ihnen zu sagen, es ist kategorisch und endgültig Recht in jedem Fall ist fehlgeleitet.
Bewegen sich auf die Umsetzung
Sobald Sie sich entschieden haben, auf Daten und das Verhalten, können Sie eine Entscheidung über die Umsetzung. Dies beinhaltet die konkreten Klassen abhängen, die über Vererbung oder Komposition.
Kann dies nicht ein großer Schritt sein, und die Menschen oft verschmelzen design und Implementierung, da es durchaus möglich ist, durch Sie laufen alle in Ihrem Kopf in ein oder zwei Sekunden und beginnen Sie mit der Eingabe entfernt.
Ein Gedankenexperiment
Einem künstlichen Beispiel: wie andere erwähnt haben, ein team ist nicht immer "nur" eine Ansammlung von Spielern. Pflegen Sie eine Auflistung der Punktestände für das team? Das team der austauschbar mit dem Verein, die Sie in Ihrem Modell? Wenn dem so ist, und wenn Ihr team der isa-Kollektion von Spielern, vielleicht ist es auch isa Erfassung von Personal und/oder eine Sammlung von Partituren. Dann sind Sie am Ende mit:
Design trotz, an dieser Stelle in C# Sie nicht in der Lage sein, um alle diese, durch Erben von List<T> wie auch immer, da C# auch "nur" unterstützt einfache Vererbung. (Wenn Sie versucht haben, diese malarky in C++, können Sie halten dies für eine Gute Sache.) Durchführung einer Erhebung über die Vererbung und über die Zusammensetzung ist wahrscheinlich fühlen schmutzig. Und Eigenschaften wie Zählen, werden die Nutzer verwirrt, es sei denn, Sie implementieren ILIst<Player>.Zählen und IList<StaffMember>.Zählen etc. explizit, und dann sind Sie einfach nur schmerzhaft, eher als verwirrend. Sie können sehen, wo das hinführt; Bauchgefühl und dachte nach unten, diesen Weg kann auch Ihnen sagen, es fühlt sich falsch an Kopf in diese Richtung (und zu Recht oder zu Unrecht, Ihre Kollegen könnten, auch wenn Sie umgesetzt wird es auf diese Weise!)
Die Kurze Antwort (Zu Spät)
Die Richtlinie nicht Erben von collection-Klassen nicht C# spezifisch, finden Sie es in vielen Programmiersprachen. Sie empfangen die Weisheit nicht ein Gesetz. Ein Grund dafür ist, dass in der Praxis der Komposition betrachtet, ist zu oft gewinnen, die über die Vererbung in Bezug auf Verständlichkeit, implementability und Wartbarkeit. Es ist eher üblich mit der realen Welt /domain-Objekte zu finden, die sinnvoll und konsistent "hasa" - Beziehungen als sinnvoll und konsistent "isa" Beziehung, es sei denn, Sie sind tief in das abstrakte, die meisten vor allem, wie die Zeit vergeht und die genauen Daten und das Verhalten der Objekte in der code-änderungen. Dies sollte nicht dazu führen, dass Sie immer Regel die Erben von collection-Klassen; aber es kann suggestiv.
InformationsquelleAutor der Antwort El Zorko
Ein Fußball-team ist nicht eine Liste der Fußball-Spieler. Ein Fußball-team besteht aus eine Liste der Fußball-Spieler!
Dies ist logisch falsch:
- und das ist richtig:
InformationsquelleAutor der Antwort sam
Es hängt vom Kontext
Wenn Sie erwägen, Ihr team, wie eine Liste von Spielern, Sie sind die Projektion der "Idee" eines Fuß-ball-team bis zu einem Aspekt: Sie reduzieren das "team" um die Menschen, die Sie sehen auf dem Feld. Diese Projektion ist nur richtig, in einem bestimmten Kontext. In einem anderen Zusammenhang, könnte dies völlig falsch. Stellen Sie sich vor Sie möchten ein sponsor des Teams. So haben Sie zu sprechen, um die Manager des Teams. In diesem Zusammenhang wird die Mannschaft voraussichtlich in die Liste der Führungskräfte. Und diese beiden Listen in der Regel nicht überlappen sehr stark. In anderen Kontexten sind die aktuellen gegen die ehemalige Spieler, etc.
Unklare Semantik
Also das problem mit der Erwägung, ein team, eine Liste der Spieler, die in Ihrer semantischen, hängt von dem Kontext und, dass es nicht erweitert werden kann, wenn sich der Kontext ändert. Zusätzlich ist es schwer, zum Ausdruck zu bringen, in welchem Kontext Sie verwenden.
Klassen sind erweiterbar
Wenn Sie mit einer Klasse mit nur einem Mitglied (z.B.
IList activePlayers
), können Sie den Namen des Mitglieds (und zusätzlich seinen Kommentar), damit der Kontext klar. Wenn es gibt weitere Kontexte, fügen Sie einfach ein zusätzliches Mitglied.- Klassen sind komplexer
In einigen Fällen ist es möglicherweise übertrieben, erstellen Sie eine zusätzliche Klasse. Jeder muss die Klassendefinition geladen werden durch den classloader und zwischengespeichert werden durch die virtuelle Maschine. Dies kostet Sie-runtime-Leistung und Speicher. Wenn Sie einen sehr spezifischen Kontext, es wäre OK, zu prüfen, ein Fußball-team als eine Liste von Spielern. Aber in diesem Fall sollte man wirklich nur verwenden
IList
, nicht eine Klasse daraus abgeleitet.Schlussfolgerung /Überlegungen
Wenn Sie einen sehr spezifischen Kontext, es ist OK, betrachten Sie ein team als eine Liste von Spielern. Zum Beispiel innerhalb einer Methode ist es völlig OK zu schreiben
Bei der Verwendung von F#, es kann sogar sein OK, um zu erstellen, eine Art Abkürzung
Aber, wenn der Kontext breiter oder sogar unklar, Sie sollte das nicht tun. Dies ist insbesondere der Fall, wenn Sie eine neue Klasse erstellen, in denen nicht klar ist, in welchem Kontext es verwendet werden kann in der Zukunft. Ein Warnzeichen ist, wenn Sie beginnen, fügen Sie zusätzliche Attribute für die Klasse (Namen der Mannschaft, Trainer, usw.). Dies ist ein klares Zeichen, dass der Kontext, in dem die Klasse verwendet wird, ist nicht festgelegt und wird sich in Zukunft ändern. In diesem Fall können Sie überlegen, das team als eine Liste von Spielern, aber Sie sollten-Modell die Liste der (aktuell aktive, nicht verletzt, etc.) Spieler, die als ein Attribut der team.
InformationsquelleAutor der Antwort stefan.schwetschke
Lassen Sie mich schreiben Sie Ihre Frage. so könnten Sie sehen, das Thema aus einer anderen Perspektive.
Wenn ich brauche, um zu repräsentieren, ein Fußball-team, ich verstehe, dass es ist im Grunde ein name. Wie: "Der Adler"
Dann später erkannte ich, dass teams, die auch Spieler haben, die.
Warum kann ich nicht nur die Erweiterung der string-Typ, so dass es hält auch eine Liste der Spieler?
Ihrem Punkt der Einreise in das problem ist beliebig. Versuchen zu denken, was macht ein team haben (Eigenschaften), nicht das, was es ist.
Nachdem Sie das tun, könnten Sie sehen, wenn es teilt sich Eigenschaften mit anderen Klassen. Und denke über Vererbung.
InformationsquelleAutor der Antwort user1852503
Macht es den Menschen ermöglicht, zu sagen
überhaupt Sinn? Wenn nicht, dann sollte es nicht eine Liste.
InformationsquelleAutor der Antwort Cruncher
Nur weil ich denke, die anderen Antworten ziemlich viel, gehen auf eine Tangente, ob ein Fußball-team "ist-ein"
List<FootballPlayer>
oder "hat-ein"List<FootballPlayer>
, die nicht wirklich diese Frage beantworten wie geschrieben.Dem OP vor allem bittet um Klärung über die Leitlinien für die Erben von
List<T>
:Weil
List<T>
hat keine virtuellen Methoden. Dies ist weniger ein problem in Ihrem code, da kann man in der Regel wechseln sich die Implementierung mit relativ wenig Schmerzen - aber kann ein viel größeres Geschäft in eine öffentliche API.Einer öffentlichen API ist eine Schnittstelle, die Sie setzen auf 3rd-party-Programmierer. Denke framework-code. Und daran erinnern, dass die Richtlinien verwiesen wird, sind die ".NET Rahmen Design-Richtlinien" und nicht "ein.NET Anwendung Design-Richtlinien". Es ist ein Unterschied, und - allgemein gesprochen - öffentliche API design ist viel strenger.
Ziemlich viel, ja. Möchten Sie vielleicht zu prüfen, die Logik dahinter zu sehen, ob es für Ihre situation gilt sowieso, aber wenn Sie nicht bauen eine öffentliche API, die Sie nicht besonders kümmern müssen-API betrifft, wie Versionierung (der, die, das ist eine Teilmenge).
Wenn Sie eine öffentliche API, die in der Zukunft, müssen Sie entweder zu Abstrakt aus der API von Ihrer Umsetzung (durch nicht setzen Ihre
List<T>
direkt) oder einem Verstoß gegen die Richtlinien mit der möglichen Zukunft, die Schmerzen, die damit verbunden sind.Hängt vom Kontext ab, aber da wir mit
FootballTeam
als ein Beispiel - stellen Sie sich vor, Sie können nicht fügen Sie eineFootballPlayer
wenn es würde dazu führen das team zu gehen, über das salary cap. Eine Möglichkeit hinzufügen, das wäre so etwas wie:Ah...aber man kann nicht
override Add
weil es nichtvirtual
(aus performance-Gründen).Wenn man in einer Anwendung (die im Grunde bedeutet, dass Sie und alle Ihre Anrufer werden gemeinsam kompiliert), dann können Sie jetzt ändern, mit
IList<T>
und beheben etwaige Fehler bei der Kompilierung:aber, wenn Sie schon öffentlich verfügbar, um eine 3rd-party-Sie hat gerade einen breaking change, das zu kompilieren, und/oder Laufzeit-Fehler.
TL;DR - die Richtlinien für die öffentliche APIs. Für private APIs, tun, was Sie wollen.
InformationsquelleAutor der Antwort Mark Brackett
Hängt es von der Verhalten Ihrer "team" - Objekt. Wenn es verhält sich genauso wie eine Sammlung, es wäre OK, zu vertreten, zunächst mit einer einfachen Liste. Dann könnten Sie beginnen zu bemerken, dass Sie halten das duplizieren von code, der wiederholt auf der Liste; an dieser Stelle haben Sie die Möglichkeit der Erstellung eines FootballTeam Objekt umschließt, die Liste der Spieler. Das FootballTeam der Klasse wird das Basisverzeichnis für alle der code, der wiederholt auf der Liste der Spieler.
Kapselung. Ihre Kunden brauchen nicht zu wissen, was geht im inneren von FootballTeam. Für alle Ihre Kunden wissen, es könnte umgesetzt werden, indem der Liste der Spieler, die sich in einer Datenbank. Sie brauchen nicht zu wissen, und dies verbessert Ihre Konstruktion.
Genau 🙂 Sie sagen footballTeam.Add(john), nicht footballTeam.Liste.Add(john). Die interne Liste wird nicht sichtbar sein.
InformationsquelleAutor der Antwort xpmatteo
Denken Sie daran, dass "Alle Modelle sind falsch, aber einige sind nützlich." -George E. P. Box
Es gibt keine "richtigen Weg", nur ein nützlich.
Wählen Sie eine, die nützlich ist für Sie und Ihre Benutzer. Das ist es.
Wirtschaftlich entwickeln, nicht "over-engineered". Je weniger code Sie schreiben, desto weniger code ein, den Sie Debuggen müssen.(Lesen Sie den folgenden Ausgaben).-- Editiert
Meine beste Antwort wäre... es hängt davon ab. Erben von einer Liste hätte setzen die Kunden dieser Klasse, um die Methoden, die möglicherweise nicht ausgesetzt werden sollte, vor allem, weil FootballTeam sieht aus wie eine business-Entität.
-- Edition 2
Grüße ich erinnere mich nicht, was ich bezog sich auf die "nicht" over-engineered" - Kommentar. Ich glaube zwar, dass die KUSS Denkweise ist eine gute Anleitung, die ich hervorheben möchte, dass die Erben einen business-class aus der Liste würde mehr Probleme schaffen als es behebt, aufgrund Abstraktion Leckage.
Auf der anderen Seite, ich glaube, es gibt eine begrenzte Anzahl von Fällen, wo einfach zu Erben aus der Liste sinnvoll ist. Wie ich schon schrieb, in der letzten Ausgabe, es hängt davon ab. Die Antwort auf jeden Fall stark beeinflusst von wissen, Erfahrung und persönlichen Vorlieben.
Dank an @kai, hilft mir zu denken, genauer gesagt, über die Antwort.
InformationsquelleAutor der Antwort Arturo Tena
Gibt es viele ausgezeichnete Antworten hier, aber ich möchte kurz auf etwas, das ich nicht sehen erwähnt: Object-oriented design ist über Stärkung Objekte.
Möchten Sie Kapseln alle Ihre Vorschriften, zusätzliche Arbeit und interne details in ein geeignetes Objekt. Auf diese Weise anderen Objekten interagieren mit diesem, nicht haben, um sorgen über alles. In der Tat, Sie wollen einen Schritt weiter gehen und aktiv verhindern anderen Objekten umgehen diese Interna.
Beim vererben von
List
alle anderen Objekte sehen können, die Sie als eine Liste. Sie haben direkten Zugriff auf die Methoden für das hinzufügen und entfernen von Spielern. Und du wirst verloren haben; zum Beispiel:Angenommen, Sie wollen sich differenzieren, wenn ein Spieler verlässt, durch wissen, ob Sie im Ruhestand, zurückgetreten oder wurden entlassen. Sie könnte die Umsetzung einer
RemovePlayer
- Methode, die einen entsprechenden input enum. Jedoch, durch übernahme vonList
Sie wäre nicht in der Lage zu verhindern, dass den direkten Zugang zuRemove
,RemoveAll
und sogarClear
. Als ein Ergebnis, Sie haben tatsächlich entmachtet IhreFootballTeam
Klasse.Zusätzliche Gedanken zur Kapselung... Sie hob die folgenden Anliegen:
Du hast Recht, das wäre unnötig verbose für alle clients verwenden die Sie team. Das problem ist jedoch sehr klein im Vergleich zu der Tatsache, dass Sie noch ausgesetzt
List Players
für alle und jeden, so dass Sie anpassen können mit Ihrem team, ohne Ihre Zustimmung.Gehen Sie auf zu sagen:
Du bist falsch über das erste bit: der Tropfen, der das Wort "Liste", und es ist eigentlich offensichtlich, dass ein team funktioniert haben Spieler.
Jedoch, Sie treffen den Nagel auf den Kopf mit der zweiten. Sie nicht möchten, dass clients aufrufen
ateam.Players.Add(...)
. Sie möchten, ruft Sieateam.AddPlayer(...)
. Und Ihre Realisierung würde (möglicherweise unter anderem) nennenPlayers.Add(...)
intern.Hoffentlich können Sie sehen, wie wichtig die Kapselung ist auf das Ziel der Stärkung Ihrer Objekte. Sie möchten, dass jede Klasse seine Arbeit zu tun, ohne Angst vor Störungen durch andere Objekte.
InformationsquelleAutor der Antwort Craig Young
Erinnert mich an die "Ist ein" versus "hat ein" Kompromiss. Manchmal ist es einfacher und makesmore Sinn zu Erben direkt von einer super-Klasse. Zu anderen Zeiten macht es mehr Sinn eine eigenständige Klasse und gehören der Klasse würden Sie geerbt haben als eine member-variable. Sie können immer noch Zugriff auf die Funktionen der Klasse sind aber nicht gebunden an die Oberfläche oder andere Einschränkungen, die möglicherweise von Erben von der Klasse.
Was tun Sie? Wie mit vielen Dingen...es hängt vom Kontext ab. Die Anleitung, die ich verwenden würde, ist, dass, um die Vererbung aus einer anderen Klasse dort wirklich sollte sein, eine "ist ein" - Beziehung. Also, wenn Sie eine schreiben Sie eine Klasse namens BMW, könnte es erbt von Auto, weil ein BMW ist wirklich ein Auto. Ein Pferd kann die Klasse erbt von der Säugetier-Klasse, weil ein Pferd eigentlich ist, ein säugetier im echten Leben und jedem Säugetier-Funktionalität sollte relevant sein Pferd. Aber kannst du sagen, dass ein team eine Liste? Was ich sagen kann, es scheint nicht wie ein Team wirklich "ist" - Liste. Also in diesem Fall würde ich eine Liste als eine member-variable.
InformationsquelleAutor der Antwort Paul J Abernathy
Mein schmutziges Geheimnis: es ist mir egal was die Leute sagen, und ich Tue es. .NET Framework ist verbreitet mit "XxxxCollection" (UIElementCollection für die Spitze von meinem Kopf Beispiel).
Also, was hält mich zu sagen:
Wenn ich es finde, besser als
Darüber hinaus, mein PlayerCollection könnte verwendet werden, durch andere Klassen, wie "Club" ohne code-Duplizierung.
Best practices von gestern, nicht von morgen. Es gibt keinen Grund, hinter den meisten best practices, die meisten sind nur Breite Zustimmung in der Gemeinschaft. Anstatt zu Fragen, die community, wenn er tadelt Sie, wenn Sie das tun, Fragen Sie sich, was ist besser lesbar und wartbar?
oder
Wirklich. Haben Sie irgendwelche Zweifel? Nun, vielleicht Sie brauchen, um zu spielen mit anderen technische Einschränkungen, die verhindern, dass Sie zur Verwendung von List<T> in der realen Anwendungsfall. Aber nicht noch eine Einschränkung, die nicht existieren sollte. Wenn Microsoft nicht dokumentieren, warum, dann ist es sicherlich eine "best practice" aus dem nichts kommen.
InformationsquelleAutor der Antwort Nicolas Dorier
Was die Richtlinien sagen, dass die öffentliche API sollte nicht offenbaren die interne design-Entscheidung, ob Sie eine Liste, ein Satz, ein Wörterbuch, einen Baum oder was auch immer. Ein "team" ist nicht unbedingt eine Liste. Sie zu implementieren, die es als eine Liste, aber die Nutzer Ihrer öffentlichen API verwenden sollten Sie auf Klasse erforderlich ist. Dies ermöglicht Ihnen, ändern Sie Ihre Entscheidung und verwenden Sie eine andere Daten-Struktur, ohne die öffentliche Schnittstelle.
InformationsquelleAutor der Antwort QuentinUK
Wenn Sie sagen
List<T>
ist "optimiert", ich denke, dass Sie möchten, um zu bedeuten, dass es nicht Funktionen wie virtuelle Methoden, die sind etwas teurer. Das problem ist also, dass, wenn Sie setzenList<T>
in Ihrem öffentliche API, verlieren Sie die Fähigkeit zum erzwingen von Geschäftsregeln oder anpassen, deren Funktionalität später. Aber, wenn Sie mit dieser geerbten Klasse als intern in Ihrem Projekt (im Gegensatz zum potentiell ausgesetzt ist, zu tausenden von Ihren Kunden/Partnern/anderen teams wie API), dann mag es OK sein, wenn es spart Zeit und es ist die Funktionalität, die Sie duplizieren möchten. Der Vorteil der Erben vonList<T>
ist, dass Sie beseitigen viele dumme wrapper-code, der ist nur nie was angepasst werden in absehbarer Zukunft. Auch, wenn Sie möchten, dass Ihre Klasse explizit haben genau die gleiche Semantik wieList<T>
für das Leben Ihrer APIs dann kann es auch OK sein.Sehe ich oft viele Leute da sind Tonnen von extra Arbeit, nur weil der FxCop Regel so sagt, oder jemand ' s blog sagt ist es eine "schlechte" Praxis. Viele Male, wendet sich dieser code in design pattern palooza Verrücktheit. Wie viel Leitlinie, behandeln Sie es als Leitfaden, dass kann Ausnahmen.
InformationsquelleAutor der Antwort ShitalShah
Wenn Ihre Klasse die Benutzer müssen alle Methoden und Eigenschaften** Liste hat, sollten Sie leiten Sie Ihre Klasse aus. Wenn Sie Sie nicht benötigen, schließen Sie die Liste und stellen Wrapper für die Methoden Ihrer Klasse Benutzer tatsächlich benötigen.
Dies ist eine strenge Regel, wenn Sie schreiben, eine öffentliche API, oder jeder andere code, der von vielen Menschen genutzt. Können Sie ignorieren diese Regel, wenn Sie haben eine winzige app und nicht mehr als 2 Entwickler. Dadurch sparen Sie einige Zeit.
Für kleine apps, können Sie auch prüfen, die Wahl einer anderen, weniger strengen Sprache. Ruby -, JavaScript - alles, was können Sie weniger code schreiben.
InformationsquelleAutor der Antwort Ivan Nikitin
Ich wollte nur hinzufügen, dass Bertrand Meyer, der Erfinder von Eiffel und design by contract, hätte
Team
Erben vonList<Player>
ohne auch nur mit der Wimper zu zucken.In seinem Buch Objekt-Orientierte Software Konstruktion, er beschreibt die Implementierung eines GUI-system, wo rechteckige Fenster Kind-Fenster. Er hat einfach
Window
vererben von beidenRectangle
undTree<Window>
Wiederverwendung der Umsetzung.Aber C# ist nicht Eiffel. Letzteres unterstützt Mehrfachvererbung und die Umbenennung von Funktionen. In C#, wenn Sie eine Unterklasse, erbt man die Schnittstelle und die Implementierung. Sie können das überschreiben der Umsetzung, aber die Aufrufkonventionen sind direkt kopiert aus der Oberklasse. In Eiffel, jedoch, Sie können ändern Sie die Namen der öffentlichen Methoden, so können Sie Sie umbenennen
Add
undRemove
zuHire
undFire
in IhremTeam
. Wenn eine Instanz vonTeam
ist Verallgemeinerung zurückList<Player>
Anrufer verwendenAdd
undRemove
um es zu ändern, aber Ihre virtuelle MethodenHire
undFire
aufgerufen werden.InformationsquelleAutor der Antwort Alexey
Während ich don ' T haben einen komplexen Vergleich, da die meisten dieser Antworten mache, möchte ich meine Methode für den Umgang mit dieser situation. Durch die Erweiterung
IEnumerable<T>
können Sie zulassen, dass IhreTeam
Klasse für die Unterstützung von Linq-Abfrage Erweiterungen, ohne öffentlich auszusetzen, die alle Methoden und Eigenschaften vonList<T>
.InformationsquelleAutor der Antwort Null511
Ich denke, ich bin nicht einverstanden mit Ihrer Verallgemeinerung. Ein team ist nicht nur eine Ansammlung von Spielern. Ein team hat so viel mehr Informationen - name, emblem, collection management/admin-Mitarbeiter, Sammlung von coaching-crew, dann Sammlung von Spielern. So richtig, Ihr FootballTeam Klasse sollte in 3 Sammlungen und nicht aus sich selbst eine Sammlung; wenn es richtig Modell der realen Welt.
Könntest du überlegen, eine PlayerCollection Klasse, die wie die Spezialisierten StringCollection bietet noch einige andere Einrichtungen - wie die Validierung und überprüft werden, bevor Sie Objekte Hinzugefügt oder entfernt werden aus dem internen Speicher.
Vielleicht die Vorstellung von einem PlayerCollection bessere Anzüge Ihre bevorzugte Ansatz?
Und dann das FootballTeam kann wie folgt Aussehen:
InformationsquelleAutor der Antwort Eniola