Was ist der Vorteil der Verwendung von Gettern und Setzern - die nur erhalten und setzen - anstatt einfach öffentliche Felder für diese Variablen zu verwenden?
Wenn Getter und Setter jemals mehr als nur das einfache Get / Set machen, kann ich dies sehr schnell herausfinden, aber ich bin nicht 100% klar, wie:
public String foo;
ist schlimmer als:
private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }
Während der erstere viel weniger Boilerplate-Code benötigt.
Antworten:
Es gibt tatsächlich viele gute Gründe , die Verwendung von Accessoren in Betracht zu ziehen, anstatt Felder einer Klasse direkt verfügbar zu machen - über das Argument der Kapselung hinaus und um zukünftige Änderungen zu vereinfachen.
Hier sind einige der Gründe, die mir bekannt sind:
quelle
public
Accessor-Methoden verursachen Codeduplizierungen und machen Informationen verfügbar. Öffentliche Accessoren sind für das Marshalling (Serialisierung) nicht erforderlich. In einigen Sprachen (Java) könnenpublic
Get-Accessoren den Rückgabetyp nicht ändern, ohne abhängige Klassen zu beschädigen. Darüber hinaus glaube ich, dass sie den OO-Prinzipien zuwiderlaufen. Siehe auch: stackoverflow.com/a/1462424/59087plane.turnTo(dir); plane.setSpeed(spd); plane.setTargetAltitude(alt); plane.getBreaks().release();
möchte ich sagenplane.takeOff(alt)
. Welche inneren Datenfelder geändert werden müssen, um die Ebene in dentakingOff
Modus zu versetzen, geht mich nichts an. Und welche anderen Objekte (breaks
) die Methode benachrichtigt, möchte ich auch nicht wissen.Da Sie in 2 Wochen (Monaten, Jahren) feststellen, dass Ihr Setter mehr als nur den Wert festlegen muss, werden Sie auch feststellen, dass die Eigenschaft direkt in 238 anderen Klassen verwendet wurde :-)
quelle
Ein öffentliches Feld ist nicht schlechter als ein Getter / Setter-Paar, das nichts anderes tut, als das Feld zurückzugeben und ihm zuzuweisen. Zunächst ist klar, dass es (in den meisten Sprachen) keinen funktionalen Unterschied gibt. Jeder Unterschied muss in anderen Faktoren wie Wartbarkeit oder Lesbarkeit liegen.
Ein oft genannter Vorteil von Getter / Setter-Paaren ist dies nicht. Es gibt diese Behauptung, dass Sie die Implementierung ändern können und Ihre Clients nicht neu kompiliert werden müssen. Angeblich können Sie mit Setzern später Funktionen wie die Validierung hinzufügen, und Ihre Kunden müssen nicht einmal darüber Bescheid wissen. Das Hinzufügen einer Validierung zu einem Setter ist jedoch eine Änderung seiner Voraussetzungen, eine Verletzung des vorherigen Vertrags , die ganz einfach lautete: "Sie können hier alles einfügen und das Gleiche später vom Getter erhalten".
Nachdem Sie den Vertrag gebrochen haben, sollten Sie jede Datei in der Codebasis ändern und nicht vermeiden. Wenn Sie dies vermeiden, gehen Sie davon aus, dass der gesamte Code davon ausgegangen ist, dass der Vertrag für diese Methoden unterschiedlich war.
Wenn dies nicht der Vertrag gewesen sein sollte, erlaubte die Schnittstelle den Clients, das Objekt in einen ungültigen Zustand zu versetzen. Das ist das genaue Gegenteil von Kapselung. Wenn dieses Feld von Anfang an nicht wirklich auf irgendetwas gesetzt werden konnte, warum war die Validierung dort nicht von Anfang an?
Das gleiche Argument gilt für andere vermeintliche Vorteile dieser Pass-Through-Getter / Setter-Paare: Wenn Sie später entscheiden, den eingestellten Wert zu ändern, brechen Sie den Vertrag. Wenn Sie die Standardfunktionalität in einer abgeleiteten Klasse überschreiben, und zwar über einige harmlose Änderungen (wie Protokollierung oder anderes nicht beobachtbares Verhalten) hinaus, brechen Sie den Vertrag der Basisklasse. Dies ist ein Verstoß gegen das Liskov-Substitutability-Prinzip, das als einer der Grundsätze von OO angesehen wird.
Wenn eine Klasse diese dummen Getter und Setter für jedes Feld hat, dann ist es eine Klasse, die überhaupt keine Invarianten hat, keinen Vertrag . Ist das wirklich objektorientiertes Design? Wenn die Klasse nur diese Getter und Setter hat, ist es nur ein dummer Datenhalter, und dumme Datenhalter sollten wie dumme Datenhalter aussehen:
Das Hinzufügen von Pass-Through-Getter / Setter-Paaren zu einer solchen Klasse bringt keinen Wert. Andere Klassen sollten sinnvolle Operationen bereitstellen, nicht nur Operationen, die Felder bereits bereitstellen. So können Sie nützliche Invarianten definieren und pflegen.
Es gibt Gründe, Getter und Setter zu verwenden, aber wenn diese Gründe nicht existieren, ist es keine gute Sache, Getter / Setter-Paare im Namen falscher Verkapselungsgötter zu bilden. Zu den gültigen Gründen, um Getter oder Setter zu erstellen, gehören die Dinge, die häufig als mögliche Änderungen erwähnt werden, die Sie später vornehmen können, z. B. die Validierung oder andere interne Darstellungen. Oder vielleicht sollte der Wert für Clients lesbar, aber nicht beschreibbar sein (z. B. das Lesen der Größe eines Wörterbuchs), sodass ein einfacher Getter eine gute Wahl ist. Aber diese Gründe sollten da sein, wenn Sie die Wahl treffen, und nicht nur als potenzielle Sache, die Sie später vielleicht wollen. Dies ist eine Instanz von YAGNI ( Du wirst es nicht brauchen ).
quelle
private
Feld zu ändern . Wenn eine Klasse keine Setter hat, ist es einfach, sie unveränderlich zu machen.Viele Leute sprechen über die Vorteile von Gettern und Setzern, aber ich möchte Devil's Advocate spielen. Im Moment debugge ich ein sehr großes Programm, in dem die Programmierer beschlossen haben, alles Getter und Setter zu machen. Das mag schön erscheinen, ist aber ein Alptraum für die Rückentwicklung.
Angenommen, Sie durchsuchen Hunderte von Codezeilen und stoßen auf Folgendes:
Es ist ein wunderschön einfacher Code, bis Sie erkennen, dass es sich um einen Setter handelt. Nun folgen Sie diesem Setter und stellen fest, dass er auch person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName setzt und person.update () aufruft, wodurch eine Abfrage an die Datenbank usw. gesendet wird. Oh, das ist wo Ihr Speicherverlust aufgetreten ist.
Das Verständnis eines lokalen Codeteils auf den ersten Blick ist eine wichtige Eigenschaft für eine gute Lesbarkeit, die Getter und Setter häufig beschädigen. Deshalb versuche ich, sie zu vermeiden, wenn ich kann, und zu minimieren, was sie tun, wenn ich sie benutze.
quelle
person.name = "Joe";
es aufgerufen wird. Die Informationen sind nicht überfüllt, die Syntaxhervorhebung zeigt, dass es sich um ein Feld handelt, und das Refactoring ist einfacher (es ist nicht erforderlich, zwei Methoden und ein Feld zu refactorisieren). Zweitens können all diese verschwendeten Gehirnzyklen, die an "getIsValid ()" denken oder "isValid ()" usw. sein sollten, vergessen werden. Ich kann mir keine Single vorstellen, wenn ich von einem Getter / Setter vor einem Fehler gerettet wurde.In einer reinen objektorientierten Welt ist Getter und Setter ein schreckliches Anti-Muster . Lesen Sie diesen Artikel: Getter / Setter. Böse. Zeitraum . Kurz gesagt, sie ermutigen Programmierer, über Objekte als Datenstrukturen nachzudenken, 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 offenlegen (keine Attribute / Eigenschaften!)
Weitere Informationen hierzu finden Sie in Abschnitt 3.5 von Elegant Objects (mein Buch über objektorientierte Programmierung).
quelle
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 aufgezeichnetes Gewicht korrigieren zu können.Es gibt viele Gründe. Mein Favorit ist, wenn Sie das Verhalten ändern oder regulieren müssen, was Sie für eine Variable festlegen können. Angenommen, Sie hatten eine setSpeed-Methode (int speed). Sie möchten jedoch, dass Sie nur eine Höchstgeschwindigkeit von 100 einstellen können. Sie würden Folgendes tun:
Was wäre, wenn Sie ÜBERALL in Ihrem Code das öffentliche Feld verwenden und dann feststellen würden, dass Sie die oben genannte Anforderung benötigen? Viel Spaß beim Aufspüren jeder Nutzung des öffentlichen Feldes, anstatt nur Ihren Setter zu modifizieren.
Meine 2 Cent :)
quelle
while(speed < 200) { do_something(); accelerate(); }
)myCar.setSpeed(157);
und nach ein paar Zeilenspeed = myCar.getSpeed();
Und jetzt ... Ich wünsche Ihnen viel Spaßspeed==100
beim Debuggen, während Sie versuchen zu verstehen, warum es sein sollte157
Ein Vorteil von Accessoren und Mutatoren besteht darin, dass Sie eine Validierung durchführen können.
Wenn es beispielsweise
foo
öffentlich war, konnte ich es leicht einstellennull
und dann konnte jemand anderes versuchen, eine Methode für das Objekt aufzurufen. Aber es ist nicht mehr da! Mit einersetFoo
Methode konnte ich sicherstellen, dass diesfoo
nie eingestellt wurdenull
.Accessoren und Mutatoren ermöglichen auch die Kapselung - wenn Sie den Wert nicht sehen sollen, sobald er festgelegt ist (möglicherweise wird er im Konstruktor festgelegt und dann von Methoden verwendet, aber niemals geändert), wird er von niemandem gesehen. Wenn Sie jedoch zulassen können, dass andere Klassen es sehen oder ändern, können Sie den richtigen Accessor und / oder Mutator bereitstellen.
quelle
Kommt auf deine Sprache an. Sie haben dieses "objektorientiert" und nicht "Java" markiert, daher möchte ich darauf hinweisen, dass die Antwort von ChssPly76 sprachabhängig ist. In Python gibt es beispielsweise keinen Grund, Getter und Setter zu verwenden. Wenn Sie das Verhalten ändern müssen, können Sie eine Eigenschaft verwenden, die einen Getter und einen Setter um den grundlegenden Attributzugriff herum umschließt. Etwas wie das:
quelle
obj.set_attr('foo')
sind, dass Klammern ( ) Gleichheitszeichen (obj.attr = 'foo'
) von Natur aus überlegen sind . Öffentlicher Zugang ist öffentlicher Zugang.obj.attr = 'foo'
nur die Variable gesetzt wird, ohne dass etwas anderes passiertobj.setAttr('foo')
"nur die Variable gesetzt wird, ohne dass etwas anderes passiert"? Wenn es sich um eine öffentliche Methode handelt, handelt es sich um eine öffentliche Methode. Wenn Sie es verwenden, um einen Nebeneffekt zu erzielen, und es öffentlich ist, sollten Sie sich besser darauf verlassen können, dass alles so funktioniert, als ob nur der beabsichtigte Nebeneffekt aufgetreten wäre (mit allen anderen Implementierungsdetails und anderen Nebenwirkungen, Ressourcennutzung, was auch immer , versteckt vor den Bedenken des Benutzers). Dies ist bei Python absolut nicht anders. Die Syntax von Python, um den Effekt zu erzielen, ist einfach.Nun, ich möchte nur hinzufügen, dass wir, selbst wenn sie manchmal für die Kapselung und Sicherheit Ihrer Variablen / Objekte notwendig sind, wenn wir ein echtes objektorientiertes Programm codieren möchten , aufhören müssen, die Accessoires zu überbeanspruchen , weil wir manchmal sehr abhängig sind auf sie wann ist nicht wirklich notwendig und das macht fast das gleiche, als ob wir die Variablen öffentlich machen.
quelle
Danke, das hat mein Denken wirklich klargestellt. Hier sind (fast) 10 (fast) gute Gründe, Getter und Setter NICHT zu verwenden:
Die letzten drei verlasse ich gerade (N / A oder D / C) ...
quelle
Ich weiß, dass es etwas spät ist, aber ich denke, es gibt einige Leute, die sich für Leistung interessieren.
Ich habe einen kleinen Leistungstest gemacht. Ich habe eine Klasse "NumberHolder" geschrieben, die eine Ganzzahl enthält. Sie können diese Ganzzahl entweder mit der Getter-Methode lesen
anInstance.getNumber()
oder direkt mit auf die Zahl zugreifenanInstance.number
. Mein Programm liest die Nummer 1.000.000.000 Mal auf beide Arten. Dieser Vorgang wird fünfmal wiederholt und die Zeit gedruckt. Ich habe folgendes Ergebnis:(Zeit 1 ist der direkte Weg, Zeit 2 ist der Getter)
Sie sehen, der Getter ist (fast) immer ein bisschen schneller. Dann habe ich es mit unterschiedlich vielen Zyklen versucht. Anstelle von 1 Million habe ich 10 Millionen und 0,1 Millionen verwendet. Die Ergebnisse:
10 Millionen Zyklen:
Mit 10 Millionen Zyklen sind die Zeiten fast gleich. Hier sind 100.000 (0,1 Millionen) Zyklen:
Auch bei unterschiedlichen Zyklen ist der Getter etwas schneller als der normale Weg. Ich hoffe das hat dir geholfen.
quelle
Verwenden Sie keine Getter-Setter, es sei denn, dies wird für Ihre aktuelle Lieferung benötigt. Denken Sie also nicht zu viel darüber nach, was in Zukunft passieren wird. Wenn etwas geändert werden muss, ist dies in den meisten Produktionsanwendungen und -systemen eine Änderungsanforderung.
Denken Sie einfach, leicht und fügen Sie bei Bedarf Komplexität hinzu.
Ich würde die Unwissenheit von Geschäftsinhabern mit tiefem technischen Know-how nicht ausnutzen, nur weil ich denke, dass es richtig ist oder ich den Ansatz mag.
Ich habe ein massives System ohne Getter-Setter geschrieben, nur mit Zugriffsmodifikatoren und einigen Methoden zur Validierung und Durchführung von Biz-Logik. Wenn Sie das unbedingt brauchten. Verwenden Sie alles.
quelle
Wir verwenden Getter und Setter:
Getter- und Setter-Methoden sind öffentliche Schnittstellen für den Zugriff auf private Klassenmitglieder.
Verkapselungsmantra
Das Kapselungsmantra besteht darin, Felder privat und Methoden öffentlich zu machen.
Obwohl die Getter- und Setter-Methoden keine neuen Funktionen hinzufügen, können wir unsere Meinung später ändern, um diese Methode zu erstellen
Überall dort, wo ein Wert verwendet werden kann, kann eine Methode hinzugefügt werden, die diesen Wert zurückgibt. Anstatt:
verwenden
In Laienbegriffen
Angenommen, wir müssen die Details dazu speichern
Person
. DiesPerson
hat die Feldername
,age
undsex
. Dabei beinhaltet Verfahren für die Erstellungname
,age
undsex
. Wenn wir nun eine andere Person erstellen müssen, müssen die Methoden fürname
,, erstelltage
werden.sex
alle immer wieder.Stattdessen können wir eine Bean
class(Person)
mit Getter- und Setter-Methoden erstellen . Morgen können wir also einfach Objekte dieser Bean erstellen,class(Person class)
wenn wir eine neue Person hinzufügen müssen (siehe Abbildung). Daher verwenden wir die Felder und Methoden der Bean-Klasse wieder, was viel besser ist.quelle
Ich habe eine ganze Weile darüber nachgedacht, was den Java-Fall betrifft, und ich glaube, die wahren Gründe sind:
Mit anderen Worten, Sie können ein Feld in einer Schnittstelle nur angeben, indem Sie eine Methode zum Schreiben eines neuen Werts und eine Methode zum Lesen des aktuellen Werts bereitstellen.
Diese Methoden sind der berüchtigte Getter und Setter ....
quelle
Es kann zum verzögerten Laden nützlich sein. Angenommen, das betreffende Objekt ist in einer Datenbank gespeichert, und Sie möchten es nur abrufen, wenn Sie es benötigen. Wenn das Objekt von einem Getter abgerufen wird, kann das interne Objekt null sein, bis jemand danach fragt. Dann können Sie es beim ersten Aufruf des Getters abrufen.
Ich hatte eine Basisseitenklasse in einem Projekt, die mir übergeben wurde und die einige Daten aus verschiedenen Webdienstaufrufen lud, aber die Daten in diesen Webdienstaufrufen wurden nicht immer auf allen untergeordneten Seiten verwendet. Webdienste bieten trotz aller Vorteile Pionierarbeit für neue Definitionen von "langsam". Sie möchten also keinen Webdienstaufruf tätigen, wenn Sie dies nicht müssen.
Ich bin von öffentlichen Feldern zu Getter gewechselt, und jetzt überprüfen die Getter den Cache. Wenn er nicht vorhanden ist, rufen Sie den Webdienst an. Mit ein wenig Umbruch wurden viele Web-Service-Anrufe verhindert.
Der Getter erspart mir also den Versuch, auf jeder untergeordneten Seite herauszufinden, was ich brauche. Wenn ich es brauche, rufe ich den Getter an und es wird für mich gefunden, wenn ich es noch nicht habe.
quelle
Ein Aspekt, den ich bisher in den Antworten vermisst habe, ist die Zugangsspezifikation:
quelle
EDIT: Ich habe diese Frage beantwortet, weil es eine Menge Leute gibt, die das Programmieren lernen, und die meisten Antworten sind sehr technisch kompetent, aber sie sind nicht so einfach zu verstehen, wenn Sie ein Neuling sind. Wir waren alle Neulinge, also dachte ich, ich würde mich an einer neulingsfreundlicheren Antwort versuchen.
Die beiden wichtigsten sind Polymorphismus und Validierung. Auch wenn es nur eine blöde Datenstruktur ist.
Nehmen wir an, wir haben diese einfache Klasse:
Eine sehr einfache Klasse, die angibt, wie viel Flüssigkeit sich darin befindet und wie hoch ihre Kapazität ist (in Millilitern).
Was passiert, wenn ich:
Nun, Sie würden nicht erwarten, dass das funktioniert, oder? Sie möchten, dass es eine Art Überprüfung der geistigen Gesundheit gibt. Und schlimmer noch, was ist, wenn ich nie die maximale Kapazität angegeben habe? Oh je, wir haben ein Problem.
Aber es gibt noch ein anderes Problem. Was wäre, wenn Flaschen nur eine Art von Behälter wären? Was wäre, wenn wir mehrere Behälter hätten, alle mit Kapazitäten und Flüssigkeitsmengen gefüllt? Wenn wir nur eine Schnittstelle erstellen könnten, könnten wir den Rest unseres Programms diese Schnittstelle akzeptieren lassen, und Flaschen, Kanister und alle möglichen Dinge würden einfach austauschbar funktionieren. Wäre das nicht besser? Da Schnittstellen Methoden erfordern, ist dies auch eine gute Sache.
Wir würden am Ende so etwas wie:
Großartig! Und jetzt ändern wir einfach die Flasche in diese:
Ich überlasse die Definition der BottleOverflowException als Übung dem Leser.
Beachten Sie nun, wie viel robuster dies ist. Wir können jetzt mit jeder Art von Container in unserem Code umgehen, indem wir LiquidContainer anstelle von Bottle akzeptieren. Und wie diese Flaschen mit solchen Dingen umgehen, kann unterschiedlich sein. Sie können Flaschen haben, die ihren Status auf die Festplatte schreiben, wenn sie sich ändern, oder Flaschen, die in SQL-Datenbanken oder GNU speichern, wissen was noch.
Und all dies kann verschiedene Möglichkeiten haben, mit verschiedenen Whoopsies umzugehen. Die Flasche prüft nur, ob sie überläuft, und löst eine RuntimeException aus. Aber das könnte falsch sein. (Es gibt eine nützliche Diskussion über die Fehlerbehandlung, aber ich halte sie hier absichtlich sehr einfach. Leute in Kommentaren werden wahrscheinlich auf die Mängel dieses simplen Ansatzes hinweisen .;))
Und ja, es scheint, als würden wir von einer sehr einfachen Idee schnell zu viel besseren Antworten gelangen.
Bitte beachten Sie auch, dass Sie die Kapazität einer Flasche nicht ändern können. Es ist jetzt in Stein gemeißelt. Sie können dies mit einem int tun, indem Sie es für endgültig erklären. Aber wenn dies eine Liste wäre, könnten Sie sie leeren, neue Dinge hinzufügen und so weiter. Sie können den Zugriff auf das Berühren der Innereien nicht einschränken.
Es gibt auch die dritte Sache, die nicht jeder angesprochen hat: Getter und Setter verwenden Methodenaufrufe. Das bedeutet, dass sie überall wie normale Methoden aussehen. Anstatt eine seltsame spezifische Syntax für DTOs und andere Dinge zu haben, haben Sie überall das Gleiche.
quelle
In Sprachen, die keine "Eigenschaften" unterstützen (C ++, Java) oder eine Neukompilierung von Clients erfordern, wenn Felder in Eigenschaften (C #) geändert werden, ist die Verwendung von get / set-Methoden einfacher zu ändern. Zum Hinzufügen einer Validierungslogik zu einer setFoo-Methode muss beispielsweise die öffentliche Schnittstelle einer Klasse nicht geändert werden.
In Sprachen, die "echte" Eigenschaften unterstützen (Python, Ruby, vielleicht Smalltalk?), Ist es sinnlos, Methoden abzurufen / festzulegen.
quelle
Eines der Grundprinzipien des OO-Designs: Verkapselung!
Es bietet Ihnen viele Vorteile. Einer davon ist, dass Sie die Implementierung des Getters / Setters hinter den Kulissen ändern können, aber jeder Verbraucher mit diesem Wert arbeitet weiter, solange der Datentyp gleich bleibt.
quelle
Sie sollten Getter und Setter verwenden, wenn:
Dies ist also sehr selten eine allgemeine OO-Frage. Es ist eine sprachspezifische Frage mit unterschiedlichen Antworten für verschiedene Sprachen (und verschiedene Anwendungsfälle).
Aus Sicht der OO-Theorie sind Getter und Setter nutzlos. Die Schnittstelle Ihrer Klasse ist das, was sie tut, nicht der Zustand. (Wenn nicht, haben Sie die falsche Klasse geschrieben.) In sehr einfachen Fällen, in denen eine Klasse nur einen Punkt in rechteckigen Koordinaten darstellt, * sind die Attribute Teil der Schnittstelle. Getter und Setter trüben das einfach. In alles anderen als sehr einfachen Fällen sind jedoch weder die Attribute noch Getter und Setter Teil der Schnittstelle.
Anders ausgedrückt: Wenn Sie der Meinung sind, dass Verbraucher Ihrer Klasse nicht einmal wissen sollten, dass Sie ein
spam
Attribut haben, und noch weniger in der Lage sind, es wohl oder übel zu ändern,set_spam
ist es das Letzte, was Sie tun möchten , ihnen eine Methode zu geben.* Selbst für diese einfache Klasse möchten Sie möglicherweise nicht unbedingt das Festlegen der Werte
x
und zulasseny
. Wenn dies wirklich eine Klasse ist, sollte es nicht haben Methoden wietranslate
,rotate
usw.? Wenn es nur eine Klasse ist, weil Ihre Sprache keine Datensätze / Strukturen / benannten Tupel hat, dann ist dies nicht wirklich eine Frage von OO…Aber niemand macht jemals allgemeines OO-Design. 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, können Sie etwas, das konzeptionell ein Attribut ist, aber tatsächlich berechnet oder validiert wird, nur über Getter und Setter darstellen.
Selbst wenn Ihre Sprache Eigenschaften hat, kann es Fälle geben, in denen sie unzureichend oder unangemessen sind. Wenn Sie beispielsweise zulassen möchten, dass Unterklassen die Semantik eines Attributs in Sprachen ohne dynamischen Zugriff steuern, kann eine Unterklasse ein Attribut nicht durch eine berechnete Eigenschaft ersetzen.
Was ist mit "Was ist, wenn ich meine Implementierung später ändern möchte?" Frage (die sowohl in der Frage des OP als auch in der akzeptierten Antwort mehrmals in unterschiedlichen Formulierungen 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 ändern, ohne die Schnittstelle zu beeinflussen. Es sei denn natürlich, Ihre Sprache unterstützt das nicht. Das ist also wirklich wieder genau der gleiche Fall.
Es ist auch wichtig, den Redewendungen der Sprache (oder des Frameworks) zu folgen, die Sie verwenden. Wenn Sie schönen Code im Ruby-Stil in C # schreiben, wird jeder erfahrene C # -Entwickler außer Ihnen Probleme haben, ihn zu lesen, und das ist schlecht. Einige Sprachen haben um ihre Konventionen herum stärkere Kulturen als andere. - und es ist kein Zufall, dass Java und Python, die sich aufgrund ihrer Redewendungen am anderen Ende des Spektrums befinden, zufällig zwei der stärksten Kulturen haben.
Über menschliche Leser hinaus wird es Bibliotheken und Tools geben, die von Ihnen erwarten, dass Sie die Konventionen befolgen und Ihr Leben schwerer machen, wenn Sie dies nicht tun. Das Verknüpfen von Widgets des Interface Builder mit anderen Objekten als ObjC oder das Verwenden bestimmter Java-Verspottungsbibliotheken ohne Getter erschwert Ihr Leben nur. Wenn die Werkzeuge für Sie wichtig sind, bekämpfen Sie sie nicht.
quelle
Unter dem Gesichtspunkt der Objektorientierung können beide Alternativen die Wartung des Codes beeinträchtigen, indem sie die Kapselung der Klassen schwächen. Eine Diskussion finden Sie in diesem ausgezeichneten Artikel: http://typicalprogrammer.com/?p=23
quelle
Getter- und Setter-Methoden sind Accessor-Methoden, dh sie sind im Allgemeinen eine öffentliche Schnittstelle zum Ändern privater Klassenmitglieder. Sie verwenden Getter- und Setter-Methoden, um eine Eigenschaft zu definieren. Sie greifen auf Getter- und Setter-Methoden als Eigenschaften außerhalb der Klasse zu, obwohl Sie sie innerhalb der Klasse als Methoden definieren. Diese Eigenschaften außerhalb der Klasse können einen anderen Namen als der Eigenschaftsname in der Klasse haben.
Die Verwendung von Getter- und Setter-Methoden bietet einige Vorteile, z. B. die Möglichkeit, Mitglieder mit ausgefeilten Funktionen zu erstellen, auf die Sie wie ähnliche Eigenschaften zugreifen können. Sie können damit auch schreibgeschützte und schreibgeschützte Eigenschaften erstellen.
Obwohl Getter- und Setter-Methoden nützlich sind, sollten Sie darauf achten, sie nicht zu stark zu verwenden, da sie unter anderem in bestimmten Situationen die Codewartung erschweren können. Außerdem bieten sie wie öffentliche Mitglieder Zugriff auf Ihre Klassenimplementierung. Die OOP-Praxis rät vom direkten Zugriff auf Eigenschaften innerhalb einer Klasse ab.
Wenn Sie Klassen schreiben, werden Sie immer aufgefordert, so viele Instanzvariablen wie möglich privat zu machen und Getter- und Setter-Methoden entsprechend hinzuzufügen. Dies liegt daran, dass Sie möglicherweise nicht möchten, dass Benutzer bestimmte Variablen in Ihren Klassen ändern. Wenn Sie beispielsweise eine private statische Methode haben, die die Anzahl der für eine bestimmte Klasse erstellten Instanzen verfolgt, möchten Sie nicht, dass ein Benutzer diesen Zähler mithilfe von Code ändert. Nur die Konstruktoranweisung sollte diese Variable bei jedem Aufruf erhöhen. In dieser Situation können Sie eine private Instanzvariable erstellen und eine Getter-Methode nur für die Zählervariable zulassen. Dies bedeutet, dass Benutzer den aktuellen Wert nur mithilfe der Getter-Methode abrufen können und keine neuen Werte festlegen können mit der Setter-Methode.
quelle
Code entwickelt sich .
private
ist ideal, wenn Sie den Schutz von Datenmitgliedern benötigen . Schließlich sollten alle Klassen eine Art "Miniprogramm" sein, das eine genau definierte Schnittstelle hat , die Sie nicht einfach mit den Interna von verschrauben können .Bei der Softwareentwicklung geht es jedoch nicht darum, die endgültige Version der Klasse so festzulegen, als würden Sie beim ersten Versuch eine gusseiserne Statue drücken. Während Sie damit arbeiten, ähnelt Code eher Ton. Es entwickelt sich, während Sie es entwickeln und mehr über die Problemdomäne erfahren, die Sie lösen. Während der Entwicklung können Klassen miteinander interagieren, als sie sollten (Abhängigkeit, die Sie herausrechnen möchten), zusammenführen oder aufteilen. Ich denke, die Debatte läuft darauf hinaus, dass Menschen nicht religiös schreiben wollen
Also hast du:
Anstatt
Es ist nicht nur
getVar()
visuell verrauscht, es gibt auch diese Illusion,gettingVar()
die irgendwie komplexer ist als es wirklich ist. Wie Sie (als Klassenschreiber) die Heiligkeit von betrachten,var
ist für einen Benutzer Ihrer Klasse besonders verwirrend, wenn er einen Durchgangssetzer hat - dann sieht es so aus, als würden Sie diese Tore aufstellen, um etwas zu "schützen", auf dem Sie bestehen, ist wertvoll. (die Heiligkeit vonvar
), aber selbst Sie geben zu, dassvar
der Schutz nicht viel wert ist, weil jemand einfach hereinkommen kann undset
var
zu jedem Wert, den er will, ohne dass Sie auch nur einen Blick auf das werfen, was er tut.Ich programmiere also wie folgt (unter der Annahme eines "agilen" Ansatzes - dh wenn ich Code schreibe, der nicht genau weiß was er tun wird / keine Zeit oder Erfahrung hat, um ein ausgeklügeltes Interface-Set im Wasserfall-Stil zu planen):
1) Beginnen Sie mit allen öffentlichen Mitgliedern für grundlegende Objekte mit Daten und Verhalten. Aus diesem Grund werden Sie in meinem gesamten C ++ - Beispielcode feststellen, dass ich ihn
struct
nichtclass
überall verwende.2) Wenn das interne Verhalten eines Objekts für ein Datenelement komplex genug wird (z. B. ein internes
std::list
in einer bestimmten Reihenfolge beibehalten möchte), werden Funktionen vom Typ Accessor geschrieben. Da ich selbst programmiere, setze ich das Mitglied nicht immerprivate
sofort, aber irgendwo in der Entwicklung der Klasse wird das Mitglied entwederprotected
oder befördertprivate
.3) Klassen, die vollständig ausgearbeitet sind und strenge Regeln für ihre Interna haben (dh sie wissen genau, was sie tun, und Sie dürfen nicht mit ihren Interna "ficken" (Fachbegriff)), erhalten die
class
Bezeichnung "Standard-Privatmitglieder". und nur einige wenige Mitglieder dürfen seinpublic
.Ich finde, dass dieser Ansatz es mir ermöglicht, nicht dort zu sitzen und religiös Getter / Setter zu schreiben, wenn viele Datenmitglieder in den frühen Stadien der Entwicklung einer Klasse migriert, verschoben usw. werden.
quelle
Es gibt einen guten Grund, die Verwendung von Accessoren in Betracht zu ziehen, da keine Eigenschaftsvererbung vorliegt. Siehe nächstes Beispiel:
Ausgabe:
quelle
Getters und Setter werden verwendet, um zwei der grundlegenden Aspekte der objektorientierten Programmierung zu implementieren:
Angenommen, wir haben eine Mitarbeiterklasse:
Hier sind die Implementierungsdetails von Full Name für den Benutzer verborgen und für den Benutzer im Gegensatz zu einem öffentlichen Attribut nicht direkt zugänglich.
quelle
Eine andere Verwendung (in Sprachen, die Eigenschaften unterstützen) besteht darin, dass Setter und Getter implizieren können, dass eine Operation nicht trivial ist. In der Regel möchten Sie vermeiden, etwas zu tun, das in einer Immobilie rechenintensiv ist.
quelle
execute
oderbuild
Verfahren.Ein relativ moderner Vorteil von Gettern / Setzern besteht darin, dass das Durchsuchen von Code in markierten (indizierten) Code-Editoren vereinfacht wird. Beispiel: Wenn Sie sehen möchten, wer ein Mitglied setzt, können Sie die Anrufhierarchie des Setters öffnen.
Wenn das Mitglied öffentlich ist, können die Tools den Lese- / Schreibzugriff auf das Mitglied nicht filtern. Sie müssen also durch alle Verwendungszwecke des Mitglieds stapfen.
quelle
In einer objektorientierten Sprache deklarieren die Methoden und ihre Zugriffsmodifikatoren die Schnittstelle für dieses Objekt. Zwischen dem Konstruktor und den Accessor- und Mutator-Methoden kann der Entwickler den Zugriff auf den internen Status eines Objekts steuern. Wenn die Variablen einfach als öffentlich deklariert werden, gibt es keine Möglichkeit, diesen Zugriff zu regulieren. Und wenn wir Setter verwenden, können wir den Benutzer für die Eingabe einschränken, die wir benötigen. Das heißt, der Feed für diese Variable wird über einen geeigneten Kanal gesendet und der Kanal wird von uns vordefiniert. Es ist also sicherer, Setter zu verwenden.
quelle
Darüber hinaus dient dies dazu, Ihre Klasse "zukunftssicher" zu machen. Insbesondere der Wechsel von einem Feld zu einer Eigenschaft ist eine ABI-Unterbrechung. Wenn Sie also später entscheiden, dass Sie mehr Logik als nur "Setzen / Abrufen des Felds" benötigen, müssen Sie ABI unterbrechen, was natürlich Probleme für alles verursacht sonst schon gegen deine Klasse kompiliert.
quelle
Ich möchte nur die Idee der Annotation werfen: @getter und @setter. Mit @getter sollten Sie in der Lage sein, obj = class.field, aber nicht class.field = obj. Mit @setter umgekehrt. Mit @getter und @setter sollten Sie in der Lage sein, beides zu tun. Dies würde die Kapselung bewahren und die Zeit verkürzen, indem zur Laufzeit keine trivialen Methoden aufgerufen werden.
quelle