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"

16voto

quillbreaker Punkte 6011

Sie kann für das "Lazy-Loading" nützlich sein. Nehmen wir an, das betreffende Objekt ist in einer Datenbank gespeichert, und Sie wollen es nur abrufen, wenn Sie es brauchen. Wenn das Objekt durch einen Getter abgerufen wird, kann das interne Objekt null sein, bis jemand danach fragt, dann kann man es beim ersten Aufruf des Getters abrufen.

In einem Projekt, das mir übergeben wurde, hatte ich eine Basisseitenklasse, die einige Daten aus verschiedenen Webdienstaufrufen lud, aber die Daten in diesen Webdienstaufrufen wurden nicht immer in allen untergeordneten Seiten verwendet. Webdienste sind trotz aller Vorteile Wegbereiter für neue Definitionen von "langsam", so dass Sie keine Webdienstaufrufe tätigen sollten, wenn Sie nicht müssen.

Ich bin von öffentlichen Feldern zu Gettern übergegangen, und jetzt prüfen die Getter den Cache, und wenn er nicht da ist, rufen sie den Webdienst auf. Mit ein wenig Wrapping wurden also eine Menge Webdienstaufrufe verhindert.

Der Getter erspart es mir also, auf jeder Child-Seite herauszufinden, was ich brauche. Wenn ich es brauche, rufe ich den Getter auf, und er sucht es für mich, wenn ich es nicht schon habe.

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }

0 Stimmen

Ruft dann der Getter den Setter auf?

0 Stimmen

Ich habe ein Codebeispiel hinzugefügt, wie ich es in der Vergangenheit getan habe - im Wesentlichen speichern Sie die tatsächliche Klasse in einem geschützten Mitglied, dann zurück, dass geschützte Mitglied in der Get-Accessor, initialisieren es, wenn es nicht initialisiert ist.

0 Stimmen

15voto

jdehaan Punkte 19398

Ein Aspekt, den ich in den bisherigen Antworten vermisst habe, ist die Zugangsspezifikation:

  • für Mitglieder haben Sie nur eine Zugangsspezifikation für das Setzen und Abrufen
  • für Setter und Getter können Sie eine Feinabstimmung vornehmen und sie separat definieren

12voto

John Millikin Punkte 190278

In Sprachen, die keine "Eigenschaften" unterstützen (C++, Java) oder eine Neukompilierung der Clients erfordern, wenn Felder in Eigenschaften umgewandelt werden (C#), ist die Verwendung von get/set-Methoden einfacher zu ändern. Das Hinzufügen einer Validierungslogik zu einer setFoo-Methode erfordert zum Beispiel keine Änderung der öffentlichen Schnittstelle einer Klasse.

In Sprachen, die "echte" Eigenschaften unterstützen (Python, Ruby, vielleicht Smalltalk?), gibt es keinen Grund für get/set-Methoden.

1 Stimmen

Re: C#. Wenn Sie Funktionalität zu einem get/set hinzufügen, würde das nicht sowieso eine Neukompilierung erfordern?

0 Stimmen

@steamer25: Entschuldigung, ich habe mich vertippt. Ich meinte, dass die Clients der Klasse neu kompiliert werden müssen.

5 Stimmen

Das Hinzufügen von Validierungslogik zu einer setFoo-Methode erfordert keine Änderung der Schnittstelle einer Klasse auf sprachlicher Ebene aber ändert sich die eigentliche Schnittstelle auch Vertrag genannt, weil er die Voraussetzungen ändert. Warum sollte man wollen, dass der Compiler dies nicht als eine brechende Änderung behandelt? wenn es sich ?

7voto

Justin Niessner Punkte 235353

Eines der Grundprinzipien des OO-Designs: Verkapselung!

Dies hat viele Vorteile, unter anderem können Sie die Implementierung des Getters/Setters hinter den Kulissen ändern, aber jeder Verbraucher dieses Wertes wird weiterhin funktionieren, solange der Datentyp derselbe bleibt.

23 Stimmen

Die Kapselung, die Getter und Setter bieten, ist lächerlich gering. Siehe ici .

0 Stimmen

Wenn Ihre öffentliche Schnittstelle angibt, dass "foo" vom Typ "T" ist und auf irgendetwas gesetzt werden kann, können Sie das niemals ändern. Sie können nicht beschließen, es zum Typ "Y" zu machen, noch können Sie Regeln wie Größenbeschränkungen auferlegen. Wenn Sie also öffentliche get/set-Felder haben, die nichts anderes tun als set/get, haben Sie nichts gewonnen, was ein öffentliches Feld nicht auch bieten würde, und machen es nur umständlicher in der Anwendung. Wenn Sie eine Einschränkung haben, wie z.B. das Objekt kann auf null gesetzt werden, oder der Wert muss innerhalb eines Bereichs liegen, dann ja, eine öffentliche set-Methode wäre erforderlich, aber Sie präsentieren immer noch einen Vertrag vom Setzen dieses Wertes, der sich nicht ändern kann

0 Stimmen

Warum kann ein Vertrag nicht geändert werden?

6voto

abarnert Punkte 332066

Sie sollten Getter und Setter verwenden, wenn:

  • Sie haben es mit etwas zu tun, das begrifflich ein Attribut ist, aber:
    • Ihre Sprache hat keine Eigenschaften (oder einen ähnlichen Mechanismus, wie die Variablenspuren von Tcl), oder
    • Die Eigenschaftsunterstützung Ihrer Sprache ist für diesen Anwendungsfall nicht ausreichend, oder
    • Die idiomatischen Konventionen Ihrer Sprache (oder manchmal Ihres Frameworks) fördern Getter oder Setter für diesen Anwendungsfall.

Es handelt sich also nur selten um eine allgemeine OO-Frage, sondern um eine sprachspezifische Frage mit unterschiedlichen Antworten für verschiedene Sprachen (und verschiedene Anwendungsfälle).


Vom Standpunkt der OO-Theorie aus sind Getter und Setter nutzlos. Die Schnittstelle Ihrer Klasse ist das, was sie tut, nicht was ihr Zustand ist. (Falls nicht, haben Sie die falsche Klasse geschrieben.) In sehr einfachen Fällen, in denen eine Klasse z.B. nur einen Punkt in rechtwinkligen Koordinaten darstellt,* sind die Attribute Teil der Schnittstelle; Getter und Setter verdecken dies nur. Aber in allen anderen als sehr einfachen Fällen sind weder die Attribute noch Getter und Setter Teil der Schnittstelle.

Mit anderen Worten: Wenn Sie glauben, dass die Verbraucher Ihrer Klasse nicht einmal wissen sollten, dass Sie eine spam Attribut zu haben, geschweige denn, es willkürlich ändern zu können, und ihnen dann eine set_spam Methode ist das Letzte, was Sie tun wollen.

* Selbst für diese einfache Klasse möchten Sie vielleicht nicht unbedingt die Einstellung der <code>x</code> y <code>y</code> Werte. Wenn dies wirklich eine Klasse ist, sollte sie dann nicht Methoden haben wie <code>translate</code> , <code>rotate</code> usw.? Wenn es nur eine Klasse ist, weil Ihre Sprache keine Records/Strukturen/benannte Tupel hat, dann ist das nicht wirklich eine Frage von OO


Aber niemand macht jemals einen allgemeinen OO-Entwurf. Sie entwerfen und implementieren in einer bestimmten Sprache. Und in einigen Sprachen sind Getter und Setter alles andere als nutzlos.

Wenn Ihre Sprache keine Eigenschaften hat, dann ist die einzige Möglichkeit, etwas darzustellen, das konzeptionell ein Attribut ist, aber tatsächlich berechnet oder validiert wird usw., die Verwendung von Gettern und Settern.

Selbst wenn Ihre Sprache über Eigenschaften verfügt, kann es Fälle geben, in denen diese unzureichend oder unangemessen sind. Wenn Sie zum Beispiel Unterklassen erlauben wollen, die Semantik eines Attributs zu kontrollieren, kann eine Unterklasse in Sprachen ohne dynamischen Zugriff ein Attribut nicht durch eine berechnete Eigenschaft ersetzen.

Was die Frage "Was ist, wenn ich meine Implementierung später ändern möchte?" betrifft (die sowohl in der Frage des Auftraggebers als auch in der akzeptierten Antwort mehrfach in unterschiedlicher Formulierung wiederholt wird): Wenn es sich wirklich um eine reine Implementierungsänderung handelt und Sie mit einem Attribut begonnen haben, können Sie es in eine Eigenschaft umwandeln, ohne die Schnittstelle zu verändern. Es sei denn natürlich, Ihre Sprache unterstützt das nicht. Es handelt sich also im Grunde um denselben Fall.

Außerdem ist es wichtig, die Idiome der Sprache (oder des Frameworks), die Sie verwenden, zu befolgen. Wenn Sie schönen Code im Ruby-Stil in C# schreiben, wird jeder erfahrene C#-Entwickler außer Ihnen Schwierigkeiten haben, ihn zu lesen, und das ist schlecht. Einige Sprachen haben eine stärkere Kultur um ihre Konventionen als andere - und es ist vielleicht kein Zufall, dass Java und Python, die am entgegengesetzten Ende des Spektrums liegen, was die Idiomatik von Gettern angeht, zufällig zwei der stärksten Kulturen haben.

Neben den menschlichen Lesern gibt es Bibliotheken und Werkzeuge, die von Ihnen erwarten, dass Sie die Konventionen einhalten, und Ihnen das Leben schwer machen, wenn Sie es nicht tun. Wenn Sie Interface Builder-Widgets mit etwas anderem als ObjC-Eigenschaften verknüpfen oder bestimmte Java-Mocking-Bibliotheken ohne Getter verwenden, machen Sie sich das Leben nur noch schwerer. Wenn die Werkzeuge für Sie wichtig sind, sollten Sie sie nicht bekämpfen.

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