1878 Stimmen

Warum Getter und Setter/Accessors verwenden?

Was ist der Vorteil der Verwendung von Gettern und Settern - die nur abfragen und setzen - anstatt einfach öffentliche Felder für diese Variablen zu verwenden?

Wenn Getter und Setter jemals mehr tun als nur das einfache Get/Set, kann ich dies sehr schnell herausfinden, aber ich bin nicht 100% klar, wie:

public String foo;

schlechter ist als:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

Ersteres hingegen erfordert viel weniger Standardcode.

8 Stimmen

10 Stimmen

Natürlich ist beides gleich schlecht, wenn das Objekt keine zu ändernde Eigenschaft benötigt. Ich würde lieber alles privat machen, und dann Getter hinzufügen, wenn es nützlich ist, und Setter, wenn es nötig ist.

31 Stimmen

Google "accessors are evil"

1217voto

LBushkin Punkte 124894

Es gibt tatsächlich viele gute Gründe die Verwendung von Accessoren zu erwägen zu verwenden, anstatt die Felder einer Klasse direkt freizulegen - abgesehen von dem Argument der Kapselung und der Erleichterung künftiger Änderungen.

Hier sind einige der Gründe, die mir bekannt sind:

  • Kapselung des Verhaltens, das mit dem Abrufen oder Setzen der Eigenschaft verbunden ist - dadurch können zusätzliche Funktionen (wie die Validierung) später leichter hinzugefügt werden.
  • Ausblenden der internen Darstellung der Eigenschaft bei gleichzeitiger Offenlegung einer Eigenschaft unter Verwendung einer alternativen Darstellung.
  • Isolierung der öffentlichen Schnittstelle von Änderungen - die öffentliche Schnittstelle kann konstant bleiben, während sich die Implementierung ändert, ohne dass die vorhandenen Verbraucher davon betroffen sind.
  • Kontrolle der Lebensdauer und der Semantik der Speicherverwaltung (Entsorgung) der Eigenschaft - besonders wichtig in nicht verwalteten Speicherumgebungen (wie C++ oder Objective-C).
  • Bereitstellung eines Debugging-Abfangpunkts für die Änderung einer Eigenschaft zur Laufzeit - das Debuggen, wann und wo eine Eigenschaft auf einen bestimmten Wert geändert wurde, kann in einigen Sprachen ohne diese Funktion recht schwierig sein.
  • Verbesserte Interoperabilität mit Bibliotheken, die dafür ausgelegt sind, mit Property Getter/Setters zu arbeiten - Mocking, Serialisierung und WPF fallen mir dazu ein.
  • Ermöglicht es den Erben, die Semantik des Verhaltens der Eigenschaft zu ändern, indem die Getter/Setter-Methoden überschrieben werden.
  • Die Getter/Setter können als Lambda-Ausdrücke und nicht als Werte weitergegeben werden.
  • Getter und Setter können unterschiedliche Zugriffsebenen zulassen - so kann z. B. das Get öffentlich, das Set aber geschützt sein.

0 Stimmen

Zum letzten Punkt: Warum könnte zum Beispiel die Menge geschützt werden?

0 Stimmen

Dies ist ein ausgezeichneter Überblick. Ein umfassendes Beispiel würde ihn noch besser machen.

2 Stimmen

@andreagalle Es gibt viele Gründe, warum das der Fall sein könnte. Vielleicht haben Sie ein Attribut, das von außen nicht verändert werden soll. In diesem Fall könnte man auch den Setter komplett entfernen. Aber vielleicht wollen Sie dieses änderungshemmende Verhalten in einer Unterklasse ändern, die dann den protected Methode.

637voto

ChssPly76 Punkte 97241

Denn wenn Sie in 2 Wochen (Monaten, Jahren) feststellen, dass Ihr Einrichter Folgendes tun muss mehr als nur den Wert zu setzen, werden Sie auch feststellen, dass die Eigenschaft direkt in 238 anderen Klassen verwendet wurde :-)

123 Stimmen

Ich sitze da und starre auf eine App mit 500k Zeilen, die nie gebraucht wurde. Das heißt, wenn sie einmal gebraucht wird, würde sie einen Wartungsalptraum verursachen. Das reicht mir für ein Häkchen.

22 Stimmen

Ich kann Sie und Ihre Anwendung nur beneiden :-) Abgesehen davon hängt es auch von Ihrem Software-Stack ab. Delphi, zum Beispiel (und C# - ich glaube?) ermöglicht es Ihnen, Eigenschaften als Bürger erster Klasse zu definieren, wo sie lesen / schreiben ein Feld direkt zunächst aber - wenn Sie es brauchen - tun dies über Getter / Setter-Methoden sowie. Sehr praktisch. In Java ist das leider nicht der Fall - ganz zu schweigen vom Javabeans-Standard, der Sie dazu zwingt, auch Getter / Setter zu verwenden.

1 Stimmen

Die Validierung ist ein klassisches Beispiel dafür, dass man im Setter etwas Besonderes tun sollte, vor allem, wenn man den Verbrauchern seines Codes nicht ganz traut...

458voto

R. Martinho Fernandes Punkte 217895

Ein öffentliches Feld ist nicht schlechter als ein Getter/Setter-Paar, das nichts anderes tut, als das Feld zurückzugeben und es zuzuweisen. Erstens ist es klar, dass es (in den meisten Sprachen) keinen funktionalen Unterschied gibt. Jeder Unterschied muss in anderen Faktoren liegen, wie Wartbarkeit oder Lesbarkeit.

Ein oft genannter Vorteil von Getter/Setter-Paaren ist das nicht. Es wird behauptet, dass man die Implementierung ändern kann und die Clients nicht neu kompiliert werden müssen. Angeblich können Sie mit Settern später Funktionen wie die Validierung hinzufügen, ohne dass Ihre Kunden davon wissen müssen. Das Hinzufügen einer Validierung zu einem Setter ist jedoch eine Änderung seiner Vorbedingungen, einen Verstoß gegen den vorherigen Vertrag Sie lautete schlicht und einfach: "Sie können hier alles hineinlegen, und Sie können das Gleiche später aus dem Getter holen".

Da Sie nun den Vertrag gebrochen haben, sollten Sie jede Datei in der Codebasis ändern wollen und nicht vermeiden. Wenn Sie dies vermeiden, gehen Sie davon aus, dass der gesamte Code davon ausgeht, dass der Vertrag für diese Methoden anders ist.

Wenn das nicht der Vertrag sein sollte, dann erlaubte die Schnittstelle den Kunden, das Objekt in einen ungültigen Zustand zu versetzen. Das ist das genaue Gegenteil von Verkapselung Wenn dieses Feld nicht von Anfang an auf irgendetwas gesetzt werden konnte, warum war die Validierung dann nicht von Anfang an vorhanden?

Dasselbe Argument gilt für andere vermeintliche Vorteile dieser "Pass-Through"-Getter-Paare: Wenn Sie sich später entscheiden, den gesetzten Wert zu ändern, brechen Sie den Vertrag. Wenn Sie die Standardfunktionalität in einer abgeleiteten Klasse überschreiben, und zwar in einer Weise, die über ein paar harmlose Änderungen hinausgeht (z. B. Protokollierung oder anderes nicht beobachtbares Verhalten), brechen Sie den Vertrag der Basisklasse. Das ist eine Verletzung des Liskovschen Substituierbarkeitsprinzips, das als einer der Grundsätze von OO gilt.

Wenn eine Klasse diese dummen Getter und Setter für jedes Feld hat, dann ist es eine Klasse, die überhaupt keine Invarianten hat, kein Vertrag . Ist das wirklich objektorientiertes Design? Wenn die Klasse nur diese Getter und Setter hat, ist sie nur ein dummer Datenhalter, und dumme Datenhalter sollten wie dumme Datenhalter aussehen:

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

Das Hinzufügen von Getter/Setter-Paaren zu einer solchen Klasse bringt keinen Mehrwert. Andere Klassen sollten sinnvolle Operationen anbieten, nicht nur Operationen, die Felder bereits anbieten. Auf diese Weise können Sie nützliche Invarianten definieren und beibehalten.

Kunde : "Was kann ich mit einem Objekt dieser Klasse tun?"
Designer : "Sie können mehrere Variablen lesen und schreiben."
Kunde : "Oh... cool, denke ich?"

Es gibt Gründe, Getter und Setter zu verwenden, aber wenn es diese Gründe nicht gibt, ist es keine gute Sache, Getter/Setter-Paare im Namen falscher Kapselungsgötter zu bilden. Gültige Gründe für Getter oder Setter sind die Dinge, die oft als mögliche Änderungen genannt werden, die man später vornehmen kann, wie Validierung oder unterschiedliche interne Darstellungen. Oder vielleicht soll der Wert für Clients lesbar, aber nicht beschreibbar sein (z. B. die Größe eines Wörterbuchs), so dass ein einfacher Getter eine gute Wahl ist. Aber diese Gründe sollten vorhanden sein, wenn Sie die Wahl treffen, und nicht nur als eine potentielle Sache, die Sie vielleicht später wollen. Dies ist eine Instanz von YAGNI ( Du wirst es nicht brauchen ).

20 Stimmen

Tolle Antwort (+1). Mein einziger Kritikpunkt ist, dass ich mehrere Lesungen brauchte, um herauszufinden, wie sich "Validierung" im letzten Absatz von "Validierung" in den ersten Absätzen unterscheidet (die Sie im letzteren Fall weggeworfen, im ersteren aber gefördert haben); eine Anpassung der Formulierung könnte in dieser Hinsicht helfen.

15 Stimmen

Das ist eine großartige Antwort, aber leider hat die heutige Zeit vergessen, was "Information Hiding" ist oder wozu es gut ist. Sie haben nie etwas über Unveränderlichkeit gelesen und in ihrem Streben nach "most agile" nie das Zustandsübergangsdiagramm gezeichnet, das definiert, was die legalen Zustände eines Objekts sind und was sie nicht sind.

121voto

Kai Punkte 9186

Viele Leute sprechen über die Vorteile von Gettern und Settern, aber ich möchte des Teufels Advokat spielen. Ich bin gerade dabei, ein sehr großes Programm zu debuggen, bei dem die Programmierer beschlossen haben, alles zu Gettern und Settern zu machen. Das mag nett erscheinen, ist aber ein Alptraum für das Reverse-Engineering.

Angenommen, Sie sehen sich Hunderte von Codezeilen an und stoßen auf diese:

person.name = "Joe";

Es ist ein schön einfaches Stück Code, bis man merkt, dass es ein Setter ist. Nun folgen Sie diesem Setter und stellen fest, dass er auch person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName setzt und person.update() aufruft, was eine Abfrage an die Datenbank sendet, usw. Oh, das ist die Stelle, an der Ihr Speicherleck auftrat.

Ein lokales Stück Code auf den ersten Blick zu verstehen, ist eine wichtige Eigenschaft der guten Lesbarkeit, die durch Getter und Setter tendenziell beeinträchtigt wird. Deshalb versuche ich, sie zu vermeiden, wenn ich kann, und zu minimieren, was sie tun, wenn ich sie verwende.

52 Stimmen

Dies ist ein Argument gegen syntaktischen Zucker, nicht gegen Setter im Allgemeinen.

0 Stimmen

@Phil Ich würde dem nicht zustimmen. Man kann genau so gut eine public void setName(String name) (in Java), das genau die gleichen Aufgaben erfüllt. O public void setFirstName(String name) das all diese Dinge tut.

1 Stimmen

@tedtanner und wenn Sie das tun, ist es kein Geheimnis mehr, dass eine Methode aufgerufen wird, da sie nicht als Feldzugriff getarnt ist.

76voto

yegor256 Punkte 96888

In einer rein objektorientierten Welt sind Getter und Setter eine Schreckliches Anti-Muster . Lesen Sie diesen Artikel: Getter/Setzer. Das Böse. Zeitraum . Kurz gesagt, sie ermutigen Programmierer, über Objekte wie über Datenstrukturen zu denken, und diese Art des Denkens ist rein prozedural (wie in COBOL oder C). In einer objektorientierten Sprache gibt es keine Datenstrukturen, sondern nur Objekte, die Verhalten zeigen (keine Attribute/Eigenschaften!).

Mehr dazu finden Sie in Abschnitt 3.5 von Elegante Objekte (mein Buch über objektorientierte Programmierung).

18 Stimmen

Interessante Sichtweise. Aber in den meisten Programmierkontexten brauchen wir Datenstrukturen. Nehmen wir das Beispiel "Hund" aus dem verlinkten Artikel. Ja, man kann das Gewicht eines realen Hundes nicht ändern, indem man ein Attribut setzt ... aber ein new Dog() ist kein Hund. Es ist ein Objekt, das Informationen über einen Hund enthält. Und für diese Verwendung ist es natürlich, ein falsch erfasstes Gewicht korrigieren zu können.

4 Stimmen

Nun, ich sage Ihnen, dass Die meisten Nützliche Programme müssen keine Objekte der realen Welt modellieren/simulieren. IMO geht es hier eigentlich gar nicht um Programmiersprachen. Es geht darum, wofür wir Programme schreiben.

5 Stimmen

Ob in der realen Welt oder nicht, yegor hat völlig recht. Wenn das, was Sie haben, wirklich eine "Struktur" ist und Sie keinen Code schreiben müssen, der sie namentlich referenziert, legen Sie sie in eine Hashtabelle oder eine andere Datenstruktur. Wenn Sie Code dafür schreiben müssen, legen Sie sie als Mitglied einer Klasse an und legen Sie den Code, der die Variable manipuliert, in dieselbe Klasse und lassen Sie die Setter und Getter weg. PS. obwohl ich größtenteils Yegors Standpunkt teile, bin ich zu der Überzeugung gelangt, dass annotierte Beans ohne Code einigermaßen nützliche Datenstrukturen sind - auch Getter sind manchmal notwendig, Setter sollten niemals existieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X