Getter und Setter werden oft als nicht richtig kritisiert. Andererseits hat der meiste OO-Code, den ich gesehen habe, umfangreiche Getter und Setter.
Wann sind Getter und Setter gerechtfertigt? Versuchen Sie, sie zu vermeiden? Sind sie im Allgemeinen überbeansprucht?
Wenn Ihre Lieblingssprache Eigenschaften hat (meine hat), werden solche Dinge auch als Stärkungsmittel für diese Frage angesehen. Aus Sicht der OO-Methodik sind sie dasselbe. Sie haben nur eine schönere Syntax.
Quellen für Kritik an Gettern / Setzern (einige stammen aus Kommentaren, um die Sichtbarkeit zu verbessern):
- http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
- http://typicalprogrammer.com/?p=23
- http://c2.com/cgi/wiki?AccessorsAreEvil
- http://www.darronschall.com/weblog/2005/03/no-brain-getter-and-setters.cfm
- http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
- http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html
Um die Kritik einfach zu formulieren: Mit Getters und Setters können Sie den internen Zustand von Objekten von außerhalb des Objekts manipulieren. Dies verletzt die Kapselung. Nur das Objekt selbst sollte sich um seinen internen Zustand kümmern.
Und eine Beispielprozedurversion des Codes.
struct Fridge
{
int cheese;
}
void go_shopping(Fridge fridge)
{
fridge.cheese += 5;
}
Mutator-Version des Codes:
class Fridge
{
int cheese;
void set_cheese(int _cheese) { cheese = _cheese; }
int get_cheese() { return cheese; }
}
void go_shopping(Fridge fridge)
{
fridge.set_cheese(fridge.get_cheese() + 5);
}
Die Getter und Setter machten den Code viel komplizierter, ohne dass eine ordnungsgemäße Kapselung möglich war. Da der interne Zustand für andere Objekte zugänglich ist, gewinnen wir durch Hinzufügen dieser Getter und Setter nicht viel.
Die Frage wurde bereits zu Stack Overflow erörtert:
quelle
Getters and setters are often criticized as being not proper OO
- Bitte zitieren.Antworten:
Getter und Setter zu haben, bricht nicht die Kapselung. Bei break encapsulation wird automatisch ein Getter und ein Setter für jedes Datenelement (jedes Feld in Java-Jargon) hinzugefügt , ohne dass darüber nachgedacht wird. Dies ist zwar besser als die Veröffentlichung aller Datenelemente, aber nur einen kleinen Schritt entfernt.
Der Punkt der Kapselung ist nicht, dass Sie den Zustand des Objekts nicht von außerhalb des Objekts kennen oder ändern können sollten, sondern dass Sie eine vernünftige Richtlinie dafür haben sollten.
Einige Datenelemente befinden sich möglicherweise vollständig im Objekt und sollten weder Getter noch Setter enthalten.
Einige Datenelemente sollten schreibgeschützt sein, daher benötigen sie möglicherweise Getter, aber keine Setter.
Einige Datenelemente müssen möglicherweise konsistent gehalten werden. In einem solchen Fall würden Sie nicht für jeden einen Setter bereitstellen, sondern eine einzige Methode, um sie gleichzeitig festzulegen, damit Sie die Werte auf Konsistenz prüfen können.
Einige Datenelemente müssen möglicherweise nur auf eine bestimmte Weise geändert werden, z. B. um einen festen Betrag inkrementiert oder dekrementiert. In diesem Fall würden Sie eine
increment()
und / oderdecrement()
Methode anstelle eines Setters angeben.Wieder andere müssen möglicherweise tatsächlich Lese- und Schreibzugriffe ausführen und haben sowohl einen Getter als auch einen Setter.
Betrachten Sie ein Beispiel für eine
class Person
. Angenommen, eine Person hat einen Namen, eine Sozialversicherungsnummer und ein Alter. Nehmen wir an, wir erlauben Menschen nicht, jemals ihren Namen oder ihre Sozialversicherungsnummer zu ändern. Das Alter der Person sollte jedoch jedes Jahr um 1 erhöht werden. In diesem Fall würden Sie einen Konstruktor bereitstellen, der den Namen und die SSN mit den angegebenen Werten initialisiert und das Alter auf 0 initialisiert. Sie würden auch eine Methode bereitstellenincrementAge()
, die das Alter um 1 erhöht Getter für alle drei. In diesem Fall sind keine Einsteller erforderlich.In diesem Entwurf können Sie zulassen, dass der Status des Objekts von außerhalb der Klasse überprüft wird, und Sie können zulassen, dass er von außerhalb der Klasse geändert wird. Sie können jedoch nicht zulassen, dass der Status willkürlich geändert wird. Es gibt eine Richtlinie, die effektiv festlegt, dass der Name und die SSN überhaupt nicht geändert werden können und dass das Alter jeweils um ein Jahr erhöht werden kann.
Nehmen wir an, eine Person hat auch ein Gehalt. Und die Leute können Jobs nach Belieben wechseln, was bedeutet, dass sich auch ihr Gehalt ändert. Um diese Situation zu modellieren, haben wir keine andere Möglichkeit, als eine
setSalary()
Methode bereitzustellen ! In diesem Fall ist es durchaus angemessen, das Gehalt nach Belieben ändern zu lassen.By the way, in Ihrem Beispiel, würde ich die Klasse gibt
Fridge
dieputCheese()
undtakeCheese()
Methoden, stattget_cheese()
undset_cheese()
. Dann hättest du noch Kapselung.quelle
Der Grund für Getter und Setter in Java ist sehr einfach:
Wenn Sie also zulassen möchten, dass ein Feld die Schnittstelle passiert, benötigen Sie eine Reader- und eine Writer-Methode. Diese werden traditionell als getX und setX für das Feld x bezeichnet.
quelle
Von http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and
JavaBean-Stil:
OO-Style:
Klar, ich bevorzuge den letzteren Ansatz. Es werden keine Implementierungsdetails ausgeblendet, es ist einfacher und präziser, und alle erforderlichen Informationen sind im Methodenaufruf enthalten, sodass es einfacher ist, die richtigen Informationen zu finden. Ich bevorzuge es auch, private Member mithilfe von Parametern im Konstruktor festzulegen, wann immer dies möglich ist.
Ihre Frage ist, wann ein Getter / Setter gerechtfertigt ist? Möglicherweise, wenn ein Moduswechsel erforderlich ist oder Sie ein Objekt nach Informationen abfragen müssen.
Als ich darüber nachdachte, als ich mit dem Codieren in C # anfing, schrieb ich viel Code in dem oben dargestellten Javabeans-Stil. Aber als ich Erfahrung in der Sprache gesammelt hatte, begann ich, mehr Elemente im Konstruktor festzulegen und Methoden zu verwenden, die eher dem obigen OO-Stil ähnelten.
quelle
Wenn das Verhalten "get" und "set" tatsächlich mit dem Verhalten in Ihrem Modell übereinstimmt, ist dies praktisch nie der Fall .
Jede andere Verwendung ist nur ein Betrug, da das Verhalten der Geschäftsdomäne nicht klar ist.
Bearbeiten
Diese Antwort hätte leichtfertig wirken können, lassen Sie mich also näher darauf eingehen. Die obigen Antworten sind größtenteils richtig, konzentrieren sich jedoch auf die Programmierparadigmen des OO-Designs und einige, die das Gesamtbild verfehlen. Nach meiner Erfahrung denken die Leute, dass das Vermeiden von Gettings und Setters eine akademische Regel für OO-Programmiersprachen ist (z. B. denken die Leute, dass das Ersetzen von Getters durch Properties großartig ist).
Tatsächlich ist es eine Konsequenz des Designprozesses. Sie müssen sich nicht mit Schnittstellen, Kapselung und Mustern befassen und darüber streiten, ob diese Paradigmen durchbrochen werden oder nicht und was eine gute OO-Programmierung ist oder nicht. Der einzige Punkt, der letztendlich wichtig ist, ist, dass Sie Ihre Domain nicht modellieren, wenn sich in Ihrer Domain nichts befindet, das so funktioniert, indem Sie es in Sie einfügen.
Die Realität ist, dass es sehr unwahrscheinlich ist, dass ein System in Ihrem Domänenbereich Getter und Setter hat. Sie können nicht zu dem Mann oder der Frau gehen, der bzw. die für die Gehaltsabrechnung verantwortlich ist, und einfach "Setzen Sie dieses Gehalt auf X" oder "Holen Sie mir dieses Gehalt" . Ein solches Verhalten gibt es einfach nicht
Wenn Sie dies in Ihren Code einfügen, entwerfen Sie Ihr System nicht so, dass es mit dem Modell Ihrer Domain übereinstimmt. Ja, das bricht Schnittstellen und Kapselung, aber das ist nicht der Punkt. Der Punkt ist, dass Sie etwas modellieren, das nicht existiert.
Außerdem fehlt Ihnen wahrscheinlich ein wichtiger Schritt oder Prozess, da es wahrscheinlich einen Grund gibt, warum ich nicht einfach zu Fuß gehen kann, um zu zahlen und zu sagen, dass Sie dieses Gehalt auf X setzen.
Wenn Leute Getter und Setter benutzen, tendieren sie dazu, die Regeln für diesen Prozess an die falsche Stelle zu verschieben. Dies entfernt sich noch mehr von Ihrer Domain. Am Beispiel der realen Welt ist es wie ein Gehalt, wenn man annimmt, dass die zufällige Person, die hereinkommt, die Erlaubnis hat, diese Werte zu erhalten, sonst würde sie nicht danach fragen. Es ist nicht nur so, wie die Domain ist, es ist auch so, wie die Domain ist.
quelle
set/get
Gehalt handelt?Getter und Setter sind in der Regel eine schlechte Idee. Wenn ein Feld nicht logisch Teil der Schnittstelle ist und Sie es als privat kennzeichnen, ist das in Ordnung. Wenn es logisch Teil der Schnittstelle ist und Sie es öffentlich machen, ist das in Ordnung. Aber wenn Sie es privat machen und dann umdrehen und es durch Bereitstellen eines Get- und Setters wieder effektiv veröffentlichen, kehren Sie zu Ihrem Ausgangspunkt zurück, mit der Ausnahme, dass Ihr Code jetzt ausführlicher und verschleierter ist.
Offensichtlich gibt es Ausnahmen. In Java müssen Sie möglicherweise Schnittstellen verwenden. Die Anforderungen an die Abwärtskompatibilität der Java-Standardbibliothek sind so hoch, dass sie normale Maße für die Codequalität überwiegen. Es ist sogar möglich, dass Sie es tatsächlich mit dem legendären, aber seltenen Fall zu tun haben, in dem es eine gute Chance gibt, dass Sie später ein gespeichertes Feld durch eine Sofortberechnung ersetzen, ohne die Benutzeroberfläche anderweitig zu beschädigen. Aber das sind Ausnahmen. Getter und Setter sind ein Anti-Pattern, das einer besonderen Begründung bedarf.
quelle
ob das Feld direkt oder über die Methode zugänglich ist, ist nicht wirklich wichtig.
Klasseninvarianten (nützliche) sind wichtig. Und um sie zu erhalten, müssen wir manchmal nicht in der Lage sein, etwas von außen zu ändern. Z.B. Wenn wir eine Klasse Square mit getrennter Breite und Höhe haben, wird sie durch Ändern einer von ihnen zu etwas anderem als einem Quadrat. Wir brauchen also die Methode changeSide. Wenn es Rectangle wäre, könnten wir Setter / public field haben. Aber Setter als würde testen, ob seine größer als Null besser wäre.
Und in konkreten Sprachen (zB Java) sind Gründe, warum wir diese Methoden (Schnittstellen) brauchen. Ein weiterer Grund für die Methode ist die Kompatibilität (Quelle und Binärdatei). Es ist also einfacher, sie hinzuzufügen, als zu überlegen, ob ein öffentliches Feld ausreichen würde.
btw. Ich verwende gerne einfache Klassen mit unveränderlichem Wert und öffentlichen Endfeldern.
quelle
Möglicherweise möchten Sie Ihre Interna in einen beliebigen Wert ändern, während die Schnittstellen unverändert bleiben. Wenn sich Ihre Schnittstellen nicht ändern, wird der Code nicht beschädigt. Sie können Ihre Interna immer noch ändern, wie Sie möchten.
quelle
Mein Ansatz ist dies -
Wenn ich später mit den Daten rechne, ist ein Getter / Setter gerechtfertigt. Wenn sich etwas ändert, schiebe ich die Daten oft in einen Getter / Setter.
Wenn es sich um eine POD-Struktur handelt, lasse ich die Slots frei.
Auf einer abstrakteren Ebene lautet die Frage "Wer verwaltet die Daten?" Und das hängt vom Projekt ab.
quelle
Wenn sich die Verwendung von Gettern und Setzern kompliziert anfühlt, liegt das Problem möglicherweise in der Sprache und nicht im eigentlichen Konzept.
Hier ist der Code aus dem zweiten Beispiel in Ruby:
Beachten Sie, dass es dem ersten Beispiel in Java sehr ähnlich sieht ? Wenn Getter und Setter als erstklassige Bürger behandelt werden, sind sie keine lästige Arbeit, und die zusätzliche Flexibilität kann manchmal ein echter Segen sein. Beispielsweise könnten wir beschließen, einen Standardwert für Käse in einem neuen Kühlschrank zurückzugeben:
Natürlich wird es viele Variablen geben, die überhaupt nicht öffentlich zugänglich gemacht werden sollten. Wenn Sie interne Variablen unnötig offenlegen, wird Ihr Code schlechter, aber Sie können Gettern und Settern kaum die Schuld geben.
quelle
Betrachten Sie eine
Size
Klasse, die Breite und Höhe einschließt. Ich kann Setter mit dem Konstruktor eliminieren, aber wie hilft mir das beim Zeichnen eines RechtecksSize
? Breite und Höhe sind keine internen Daten für die Klasse. Es handelt sich um gemeinsam genutzte Daten, die den Verbrauchern von Size zur Verfügung stehen müssen.Objekte bestehen aus Verhalten und Zustand - oder Attributen. Wenn es keinen exponierten Zustand gibt, sind nur die Verhaltensweisen öffentlich.
Wie würden Sie ohne Staat eine Sammlung von Objekten sortieren? Wie würden Sie nach einer bestimmten Instanz eines Objekts suchen? Was passiert, wenn Sie nur Konstruktoren verwenden, wenn Ihr Objekt über eine lange Liste von Attributen verfügt?
Kein Methodenparameter sollte jemals ohne Validierung konsumiert werden. Deshalb ist es faul zu schreiben:
Wenn Sie es so schreiben, haben Sie sich zumindest darauf vorbereitet, den Setter für die Validierung zu verwenden. es ist besser als ein öffentliches Feld - aber gerade noch. Zumindest verfügen Sie jedoch über eine konsistente öffentliche Schnittstelle, über die Sie Validierungsregeln festlegen können, ohne den Code Ihrer Kunden zu verletzen.
Getter, Setter, Eigenschaften, Mutatoren, nennen Sie sie, wie Sie wollen, aber sie sind notwendig.
quelle
int
Beispiel eine Instanzvariable und stellen Sie sich vor, Sie möchten eine Validierungsregel hinzufügen, um nur nicht negative Werte zu akzeptieren. Das Problem ist, dass der Code Ihres Kunden möglicherweise bereits auf der Möglichkeit beruht, ihn auf einen negativen Wert zu setzen ...Wenn Getter und Setter die Kapselung und die wahre OO verletzen, dann habe ich ernsthafte Probleme.
Ich hatte immer das Gefühl, dass ein Objekt das darstellt, woran man am besten denkt, dass man es braucht.
Ich habe gerade ein Programm geschrieben, das Mazes in Java generiert, und ich habe eine Klasse, die "Maze Squares" repräsentiert. Ich habe Daten in dieser Klasse, die Koordinaten, Wände und Boolesche Werte usw. darstellen.
Ich muss eine Möglichkeit haben, diese Daten zu ändern / zu manipulieren / darauf zuzugreifen! Was mache ich ohne Getter und Setter? Java verwendet keine Eigenschaften und das Festlegen aller meiner Daten, die für diese Klasse lokal sind, als öffentlich ist definitiv ein Verstoß gegen die Kapselung und OO.
quelle
Erstens gibt es im Großen und Ganzen zwei Arten von Objekten, die ich kommentieren werde: Wert- und Servicetypen.
Diensttypen sollten niemals Setter haben. Welche Abhängigkeiten auch immer sie benötigen, sollten nicht abrufbar sein. Die beste Möglichkeit, Abhängigkeiten zu übergeben, besteht in der Verwendung eines Konstruktors oder einer Factory. Auf diese Weise werden alle Instanzen von Anfang an vollständig gebildet.
Werttypen sollten auch unveränderlich sein. Andererseits gibt es Zeiten, in denen dies nicht praktikabel ist, wie z. B. ein ORM oder eine andere Zuordnung, z. B. von einem Widget zu einem Objekt. Alle anderen Werttypen, die vom einen Layer oder Teil zum anderen um das System herum übertragen werden, sollten unveränderlich sein und keine Setter haben.
quelle
Ein Getter / Setter ist wie jede andere öffentliche Methode gerechtfertigt. Die Rechtfertigung liegt hauptsächlich darin, dass wir eine Schnittstelle zur Außenwelt bereitstellen möchten, die definiert, wie unsere Klasse mit anderen Klassen interagiert. Wir tun dies hauptsächlich, weil wir die Kopplung zwischen getrennten Einheiten reduzieren wollen. Das Reduzieren der Kopplung ist aus vielen Gründen eine gute Sache:
quelle
Ja, Getter und Setter sind ein Anti-Pattern in der objektorientierten Programmierung und sollten niemals verwendet werden: http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html . Kurz gesagt, sie passen nicht in ein objektorientiertes Paradigma, weil sie Sie ermutigen, ein Objekt wie eine Datenstruktur zu behandeln. Welches ist ein großer Irrtum.
quelle
Ich hoffe, dass alles, was die von der Firma, die Ihre Programmiersprache entwickelt, entwickelte IDE automatisch generiert, nicht gegen die "Prinzipien der Objektorientierung" verstößt.
Das heißt, wenn Sie eine Variable mit öffentlichem Gültigkeitsbereich haben, verwenden Sie einen Getter und einen Setter, und Sie sind golden. Scheint für mich das notwendige Element des extrem objektorientierten Kapselungsprinzips zu sein - auch wenn es nur nach viel Junk-Code aussieht.
Der Grund für die Verwendung ist, dass die ordnungsgemäße Verkapselung möglicherweise noch stattfindet. Solange Sie die Ebene entfernt haben, mit der die Person, die mit Ihrem Objekt spielt, Ihr Objekt fühlt, können Sie das Objekt entfernen, ohne dass er es überhaupt weiß, oder?
Es genügt zu sagen, ein geteiltes Haus kann nicht bestehen, einer der Mieter von OO wird sich nicht selbst anmachen, und Sie können nicht sowohl der Kapselung als auch der vorzeitigen Optimierung dienen.
quelle
Ich dachte, wir hätten hier üblichere Antworten?
Getter und Setter sind im Allgemeinen extrem OOP (jeder, der etwas anderes sagt, ist falsch, so einfach ist das).
Obwohl Sie sich daran erinnern müssen, nicht zu viel zu entwickeln, sollten Sie niemals einen Getter oder Setter erstellen, der nicht benötigt wird. Alle Informationen, die Sie nicht von einer anderen Klasse verwenden werden, für die Sie keinen Getter oder Setter haben sollten.
Der Grund, warum Sie Felder nicht veröffentlichen und stattdessen Getter und Setter haben, ist meistens:
Es ist nicht möglich, ordnungsgemäße Tests mithilfe von Feldern durchzuführen. Getter / Setter sind in dieser Hinsicht viel besser.
Es ist unmöglich, Felder in einer Echtzeit-Programmiereinstellung richtig zu verwenden. Synchronisierte Getter / Setter sind der richtige Weg.
Das Oberflächenthema (bereits erklärt, damit ich es nicht tue).
Es ist einfacher zu verwenden, wenn das System ordnungsgemäß wiederverwendet wird.
Es ist viel schwieriger zu wissen, welche Klassen Ihre Klasse verwenden und was beim Ändern eines Feldes kaputt geht als ein Getter / Setter.
Aus diesem Grund verwenden Sie ein öffentliches Feld nur dann, wenn Sie kein offizielles Projekt erstellen, sondern es nur zum Spaß tun und sich nicht um die Getter / Setter kümmern.
quelle