Ich habe eine Klasse mit einer Variablen, die privat ist, und die Klasse hat einen Getter und einen Setter für diese Variable. Warum diese Variable nicht öffentlich machen?
Der einzige Fall, den ich denke, dass Sie Getter und Setter verwenden müssen, ist, wenn Sie eine Operation neben dem Set oder dem Get ausführen müssen. Beispiel:
void my_class::set_variable(int x){
/* Some operation like updating a log */
this->variable = x;
}
this->variable = x + 5
eineUpdateStatistics
Funktion im Setter ausführen oder aufrufen , was in diesen Fällenclassinstancea->variable = 5
zu Problemen führt.set_inch
,set_centimeter
,get_inch
,get_centimeter
, mit einigen gruseligen Aktionen.Antworten:
Haben Sie jemals von einer Immobilie gehört?
Eine Eigenschaft ist ein Feld mit "eingebauten" Zugriffsmechanismen (Gettern und Setzern). Java zum Beispiel hat keine Eigenschaften, aber es wird empfohlen, die Getter und Setter in ein privates Feld zu schreiben. C # hat Eigenschaften.
Also, warum brauchen wir Getter und Setter? Grundsätzlich brauchen wir es, um das Feld zu schützen / abzuschirmen . Wenn Sie beispielsweise nicht auf das Feld in der Speicherreferenz zugreifen, greifen Sie auf eine Methode zu, mit der das Feld (die Referenz) geändert wird. Diese Methode ist in der Lage, einige Vorgänge auszuführen, die ein Benutzer nicht wissen möchte ( Verkapselung von Verhalten ), wie in Ihrem Beispiel. Stellen Sie sich zum Beispiel vor, dass ein Dutzend Klassen Ihr öffentliches Feld verwenden und Sie die Art und Weise ändern müssen, wie es verwendet wird. Sie müssten sich jede dieser Klassen ansehen, um die Art und Weise zu ändern, in der sie das Feld verwenden also "OOlysh".
Aber zum Beispiel, wenn Sie ein boolesches Feld haben, das als tot bezeichnet wird. Sie sollten zweimal überlegen, bevor Sie setDead und isDead deklarieren. Sie sollten für Menschen lesbare Accessoren schreiben , z. B. kill () anstelle von setDead.
Es gibt jedoch viele Frameworks, die davon ausgehen, dass Sie die JavaBean-Namenskonvention befolgen (hier wird über Java gesprochen). In diesen Fällen sollten Sie daher alle Get- und Setter deklarieren, die der Namenskonvektion folgen.
quelle
foo.bar = biz.baz+5
eine Funktionbiz
zum Auswerten aufgerufenbaz
, dann fünf hinzugefügt und eine Funktionfoo
zum Festlegenbar
des resultierenden Werts aufgerufen wird. Solche Überladungen werden nicht als "Eigenschaften" bezeichnet, können jedoch denselben Zweck erfüllen.Dies ist nicht die populärste Meinung, aber ich sehe keinen großen Unterschied.
Setter und Getter sind eine ziemlich schlechte Idee. Ich habe darüber nachgedacht und ehrlich gesagt kann ich in der Praxis keinen Unterschied zwischen einem Setter / Getter einer Eigenschaft und einer öffentlichen Variablen finden.
In THEORY fügen ein Setter und Getter oder eine Eigenschaft einen Ort hinzu, an dem zusätzliche Aktionen ausgeführt werden können, wenn eine Variable gesetzt / geholt wird. Theoretisch isolieren sie Ihren Code von Änderungen.
In Wirklichkeit sehe ich selten Setter und Getter, die zum Hinzufügen einer Aktion verwendet werden, und wenn Sie eine Aktion hinzufügen möchten, möchten Sie sie ALLEN Settern oder Gettern einer Klasse (wie dem Protokollieren) hinzufügen, die Sie zu der Annahme veranlassen sollten, dass dies erforderlich ist sei eine bessere Lösung.
Wenn Sie beim Isolieren von Entwurfsentscheidungen ein Int in ein Long ändern, müssen Sie immer noch Ihre Setter ändern und mindestens jede Zeile überprüfen, die von Hand darauf zugreift - da ist nicht viel Isolation.
Veränderliche Klassen sollten ohnehin standardmäßig vermieden werden, daher sollte das Hinzufügen eines Setters das letzte Mittel sein. Dies wird durch das Builder-Muster verringert, bei dem ein Wert festgelegt werden kann, bis sich das Objekt in einem gewünschten Zustand befindet. Dann kann die Klasse unveränderlich werden und Ihre Setter Ausnahmen auslösen.
Was Getter betrifft, kann ich immer noch keinen großen Unterschied zwischen einem Getter und einer öffentlichen Endvariablen feststellen. Das Problem hierbei ist, dass es in beiden Fällen schlecht ist. Sie sollten nicht nach einem Wert von einem Objekt fragen und daran arbeiten - Sie sollten ein Objekt bitten, eine Operation für Sie durchzuführen.
Übrigens befürworte ich keine öffentlichen Variablen - ich sage, Setter und Getter (und sogar Eigenschaften) sind viel zu nahe dran, bereits öffentliche Variablen zu sein.
Das große Problem ist einfach, dass Leute, die keine OO-Programmierer sind, zu versucht sind, Setter und Getter zu verwenden, um Objekte in Eigenschaftskugeln (Strukturen) zu verwandeln, die herumgereicht und bearbeitet werden, so ziemlich das Gegenteil von der Funktionsweise von objektorientiertem Code.
quelle
Der Benutzer von Gettern und Setzern befasst sich mit dem Prinzip der Kapselung . Auf diese Weise können Sie die Funktionsweise innerhalb der Klasse ändern und alles am Laufen halten.
Wenn zum Beispiel 3 andere Objekte aufrufen
foo.bar
, um den Wert von bar zu erhalten, und Sie beschließen, den Namen von bar so weit zu ändern, dass Sie ein Problem haben. Wenn die Objekte aufgerufenfoo.bar
würden, müssten Sie alle Klassen ändern, die dies haben. Wenn ein Setter / Getter verwendet wird, müssen Sie nichts ändern. Eine andere Möglichkeit besteht darin, den Typ der Variablen zu ändern. In diesem Fall fügen Sie dem Getter / Setter einfach etwas Transformationscode hinzu, und schon geht es Ihnen gut.quelle
Mit Gettern und Setzern können Sie auch steuern, welche Inhalte in einer bestimmten Variablen gespeichert werden. Wenn der Inhalt einen bestimmten Typ oder Wert haben muss, kann ein Teil Ihres Setter-Codes sicherstellen, dass der neue Wert diese Anforderungen erfüllt. Wenn die Variable öffentlich ist, können Sie nicht sicherstellen, dass diese Anforderungen erfüllt sind.
Dieser Ansatz macht Ihren Code außerdem anpassungsfähiger und verwaltbarer. Es ist viel einfacher, Änderungen an der Architektur einer Klasse vorzunehmen, wenn Funktionen vorhanden sind, die diese Architektur vor allen anderen Klassen oder Funktionen, die diese Klasse verwenden, verbergen. Die bereits erwähnte Änderung eines Variablennamens ist nur eine von vielen Änderungen, die viel einfacher durchzuführen sind, wenn Sie Funktionen wie Getter und Setter haben. Die allgemeine Idee ist, so viel wie möglich privat zu halten, insbesondere Ihre Klassenvariablen.
quelle
Sie sagen: "Ich denke, Sie müssen Getter und Setter nur dann verwenden, wenn Sie eine andere Operation als das Set oder das Get ausführen müssen."
Sie sollten Getter und Setter verwenden, wenn Sie zu einem späteren Zeitpunkt möglicherweise eine andere Operation als set and get ausführen müssen und in diesem Fall nicht Tausende von Quellcodezeilen ändern möchten.
Sie sollten Getter und Setter verwenden, wenn Sie nicht möchten, dass jemand die Adresse der Variablen nimmt und weitergibt, was katastrophale Folgen hat, wenn diese Variable dann geändert werden kann, ohne dass der Quellcode dies erwähnt, oder auch nachdem das Objekt nicht mehr vorhanden ist .
quelle
Lassen Sie uns zunächst das Paradigma klarstellen.
Wo ist ein Getter / Setter nützlich?
Sind Getter / Setter in Datenstrukturen nützlich? Nein.
Eine Datenstruktur ist eine Speicherlayoutspezifikation, die einer Reihe von Funktionen gemeinsam ist und von diesen manipuliert wird.
Im Allgemeinen kann jede alte neue Funktion eine Datenstruktur manipulieren, wenn dies so geschieht, dass die anderen Funktionen es noch verstehen können, dann wird die Funktion der Familie hinzugefügt. Ansonsten ist es eine Schurkenfunktion und eine Fehlerquelle.
Verstehen Sie mich nicht falsch, es könnte mehrere Funktionsfamilien geben, die überall über diese Datenstruktur mit Snitches, Turncoats und Double-Agents streiten. Es ist in Ordnung, wenn jeder seine eigene Datenstruktur hat, mit der er spielen kann, aber wenn er sie teilt ... Stellen Sie sich vor, mehrere kriminelle Familien sind sich nicht einig über Politik, es kann sehr schnell zu einem Durcheinander kommen.
Gibt es eine Möglichkeit, die Datenstruktur zu verschlüsseln, damit Schurkenfunktionen nicht alles durcheinander bringen, wenn die erweiterten Funktionsfamilien dies erreichen können? Ja, sie heißen Objekte.
Sind Getter / Setter in Objekten nützlich? Nein.
Der springende Punkt beim Einbinden einer Datenstruktur in ein Objekt war, sicherzustellen, dass keine unerwünschten Funktionen vorhanden sind. Wenn die Funktion der Familie beitreten wollte, musste sie zuerst gründlich überprüft werden und dann Teil des Objekts werden.
Der Zweck eines Get- und Setters besteht darin, Funktionen außerhalb des Objekts die Möglichkeit zu geben, das Speicherlayout des Objekts direkt zu ändern. Das klingt nach einer offenen Tür, die es Schurken erlaubt ...
Der Edge-Fall
Es gibt zwei Situationen, in denen ein öffentlicher Getter / Setter Sinn macht.
Container und Containerschnittstellen sind perfekte Beispiele für diese beiden Situationen. Der Container verwaltet die Datenstrukturen (verknüpfte Liste, Karte, Baum) intern, übergibt jedoch die Kontrolle über das spezifische Element an alle und verschiedene. Die Schnittstelle abstrahiert dies und ignoriert die Implementierung vollständig und beschreibt nur die Erwartungen.
Leider machen viele Implementierungen das falsch und definieren die Schnittstelle dieser Art von Objekten, um einen direkten Zugriff auf das eigentliche Objekt zu ermöglichen. So etwas wie:
Das ist kaputt. Die Implementierungen von Container müssen die Kontrolle über ihre Interna explizit an denjenigen übergeben, der sie verwendet. Ich habe noch keine Sprache mit veränderlichem Wert gesehen, bei der dies in Ordnung ist (Sprachen mit Semantik mit unveränderlichem Wert sind per Definition in Bezug auf Datenkorruption in Ordnung, jedoch nicht unbedingt in Bezug auf Datenspionage).
Sie können den Get / Setter verbessern / korrigieren, indem Sie nur die Kopiersemantik oder einen Proxy verwenden:
Möglicherweise könnte eine Rogue-Funktion hier noch Chaos anrichten (mit genügend Aufwand sind die meisten Dinge möglich), aber die Kopiersemantik und / oder der Proxy verringern die Wahrscheinlichkeit für eine Reihe von Fehlern.
Private Getter / Setter
Dies ist die letzte Bastion von Gettern und Setzern, die direkt an dem Typ arbeiten. Tatsächlich würde ich diese Getter und Setter nicht einmal als Accessoren und Manipulatoren bezeichnen.
In diesem Zusammenhang erfordert die Manipulation eines bestimmten Teils der Datenstruktur manchmal immer / fast immer / im Allgemeinen eine bestimmte Buchführung. Sagen wir, wenn Sie das Stammverzeichnis eines Baums aktualisieren, muss der Look-Aside-Cache gelöscht werden, oder wenn Sie auf das externe Datenelement zugreifen, muss eine Sperre erlangt / aufgehoben werden. In diesen Fällen ist es sinnvoll, den DRY-Principal anzuwenden und diese Aktionen zusammenzufassen.
Im privaten Kontext ist es für die anderen Funktionen in der Familie immer noch möglich, diese "Get-and-Setter" zu umgehen und die Datenstruktur zu manipulieren. Deshalb betrachte ich sie eher als Accessoren und Manipulatoren. Sie können direkt auf die Daten zugreifen oder sich auf ein anderes Familienmitglied verlassen, um diesen Teil richtig zu machen.
Geschützte Getter / Setter
In einem geschützten Kontext unterscheidet es sich nicht sonderlich von einem öffentlichen Kontext. Fremd möglicherweise Rogue-Funktionen wollen Zugriff auf die Datenstruktur. Also nein, wenn sie existieren, funktionieren sie wie öffentliche Getter / Setter.
quelle
Aus C ++ - Erfahrung ist der Setter / Getter für zwei Szenarien hilfreich:
Abgesehen davon ist Sicherheit ein wichtiger Punkt, aber seine Bedeutung ist auf sehr wenige Entwicklungsanwendungen wie Login- oder Datenbankzugriffsmodule beschränkt. Warum sich die Mühe machen, extra zu programmieren, wenn nur wenige Leute Ihr Modul benutzen?
quelle