Ich habe diese Seite gelesen , ungefähr wann Getter / Setter gerechtfertigt sind, und das OP hat das folgende Codebeispiel gegeben:
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 akzeptierte Antwort lautet:
By the way, in Ihrem Beispiel, würde ich die Klasse gibt
Fridge
dieputCheese()
undtakeCheese()
Methoden, stattget_cheese()
undset_cheese()
. Dann hätten Sie noch Kapselung.
Wie wird die Kapselung erhalten, indem sie von get / set in putCheese()
/ umbenannt wird takeCheese()
? Sie erhalten / setzen offensichtlich einen Wert. Warum also nicht einfach als get / set belassen?
In derselben Antwort heißt es auch:
Getter und Setter zu haben, bricht an sich nicht die Kapselung. Die Unterbrechungskapselung fügt automatisch einen Getter und einen Setter für jedes Datenelement (jedes Feld in Java-Jargon) hinzu, ohne darüber nachzudenken.
In diesem Fall haben wir nur eine Variable, cheese
und Sie können den Käse nehmen und in den Kühlschrank zurückgeben, sodass in diesem Fall ein Get / Set-Paar gerechtfertigt ist.
quelle
putCheese
würde dem Kühlschrank Käse hinzufügen undtakeCheese
ihn entfernen - dies sind (übergeordnete) domänenorientierte Abstraktionen und keine Objektfeld-Getter und -Setter (die (untergeordnete) Computerprogrammierungsabstraktionen sind).Antworten:
Ich denke, Sie verpassen den Punkt. Es heißt nicht, dass Sie den Setter und Getter umbenennen sollten, sondern Methoden, mit denen Sie Gegenstände zum Kühlschrank hinzufügen und daraus entfernen können. dh
Jetzt ist die private Variable gekapselt. Ich kann es nicht einfach auf alles einstellen, was ich will, ich kann nur Käsescheiben mit den Methoden hinzufügen und aus dem Kühlschrank entfernen, die wiederum sicherstellen, dass alle von mir gewünschten Regeln für die Käsegeschäftslogik angewendet werden.
quelle
setCheese()
hätten Sie dieselbe Logik im Setter. Für mich jedenfalls versuchen Sie, die Tatsache zu verbergen, dass Sie einen Setter verwenden, indem Sie die Methode umbenennen, aber Sie haben offensichtlich etwas.AddCheese(Integer.MAX_VALUE)
sollte dies fehlschlagen, wird es aber nicht.Getter und Setter unterbrechen per Definition jedes Mal die Kapselung . Was könnte argumentiert werden, dass manchmal müssen wir das tun. Hier sind meine Antworten:
Der Unterschied liegt in der Semantik, dh in der Bedeutung dessen, was Sie schreiben. Bei der Kapselung geht es nicht nur darum, den inneren Zustand zu schützen, sondern ihn zu verbergen . Der interne Status sollte nicht einmal außerhalb bekannt sein. Stattdessen wird erwartet, dass das Objekt geschäftsrelevante Methoden (manchmal als "Verhalten" bezeichnet) zur Manipulation / Verwendung dieses Status bietet.
Also
get
undset
sind Fachbegriffe und scheinen nichts mit der "Kühlschrank" -Domäne zu tun zu haben, währendput
undtake
könnten tatsächlich einen Sinn ergeben.Jedoch , ob
put
odertake
macht tatsächlicher noch Sinn von den Anforderungen abhängt und nicht objektiv beurteilt werden kann. Siehe nächster Punkt:Das kann ohne mehr Kontext nicht objektiv bestimmt werden. Ihr Beispiel enthält eine
go_shopping()
andere Methode. Wenn das ist , was dasFridge
ist für, als sie es nicht brauchenget
oderset
, was es braucht , istFridge.go_shopping()
. Auf diese Weise haben Sie eine Methode, die aus den Anforderungen abgeleitet wird. Alle benötigten "Daten" sind lokal und Sie haben tatsächliches Verhalten anstelle einer nur dünn verschleierten Datenstruktur.Denken Sie daran, dass Sie kein generisches, wiederverwendbares Produkt erstellen
Fridge
. Sie bauen ein nurFridge
für Ihre Anforderungen. Jeder Aufwand, der aufgewendet wird, um mehr als das zu erreichen, was es sein muss, ist tatsächlich verschwenderisch.quelle
Getters and setters break encapsulation every single time
- Das ist etwas zu stark für meinen Geschmack formuliert. Methoden (einschließlich Getter und Setter) haben den gleichen Zweck wie Gates bei einem Konzert: Sie ermöglichen den ordnungsgemäßen Ein- und Ausstieg aus dem Veranstaltungsort.public int getFoo()
es in der Praxis fast unmöglich, zu einem anderen Typ zu wechseln.Fast alles zeigt ein grundlegendes Missverständnis der Kapselung und ihrer Anwendung.
Die anfängliche Antwort, dass Sie die Kapselung unterbrochen haben, ist einfach falsch. Bei Ihrer Anwendung muss möglicherweise einfach der Wert des Käses im Kühlschrank eingestellt werden, anstatt ihn zu erhöhen / verringern oder hinzuzufügen / zu entfernen. Es ist auch keine Semantik, egal wie Sie es nennen. Wenn Sie auf Attribute zugreifen und / oder diese ändern müssen, unterbrechen Sie die Kapselung nicht, indem Sie sie bereitstellen. Schließlich geht es bei der Kapselung nicht wirklich darum, sich zu "verstecken", sondern darum, den Zugriff auf Status und Werte zu steuern, die außerhalb der Klasse nicht öffentlich sein oder manipuliert werden müssen, während sie denjenigen gewährt werden, die die intern zur Verfügung gestellte Aufgabe ausführen sollen.
Ein Getter oder Setter unterbricht die Kapselung nicht, wenn ein legitimer Bedarf besteht, einen Wert abzurufen oder festzulegen. Deshalb können Methoden veröffentlicht werden.
Bei der Kapselung geht es darum, Daten und die Methoden, mit denen diese Daten direkt geändert werden, an einem logischen Ort, der Klasse, zusammenzuhalten.
In diesem speziellen Fall besteht eindeutig die Notwendigkeit, den Wert von Käse in der Anwendung zu ändern. Unabhängig davon, wie dies erfolgt, über get / set oder add / remove, solange die Methoden in der Klasse gekapselt sind, folgen Sie dem objektorientierten Stil.
Zur Verdeutlichung werde ich ein Beispiel geben, wie die Kapselung durch Bereitstellung des Zugriffs unabhängig vom Methodennamen oder der logischen Ausführung unterbrochen wird.
Angenommen, Ihr Kühlschrank hat eine "Lebensdauer", nur einige Zecken, bevor der Kühlschrank nicht mehr betriebsbereit ist (aus Gründen der Argumentation kann der Kühlschrank nicht repariert werden). Logischerweise kann ein Benutzer (oder der Rest Ihrer Anwendung) diesen Wert auf keinen Fall ändern. Es sollte privat sein. Es wäre nur durch ein anderes öffentliches Attribut sichtbar, das als "isWorking" bekannt ist. Wenn die Lebensdauer abläuft, ist der Kühlschrank intern auf false eingestellt.
Die Ausführung des Countdowns für die Lebensdauer und das Umlegen des isWorking-Schalters erfolgt vollständig im Kühlschrank. Nichts außerhalb könnte / sollte den Prozess beeinflussen können. isWorking sollte nur sichtbar sein, damit ein Getter die Kapselung nicht unterbricht. Das Hinzufügen von Accessoren für Elemente des Lebensdauerprozesses würde jedoch Ihre Kapselung beschädigen.
Wie die meisten Dinge ist die Definition der Kapselung nicht wörtlich, sondern relativ. Sollten Sie X außerhalb der Klasse sehen können? Sollten Sie in der Lage sein, Y zu ändern? Ist alles, was für Ihr Objekt hier in dieser Klasse gilt, oder ist die Funktionalität auf mehrere Klassen verteilt?
quelle
Es geht nicht nur darum, eine Methode umzubenennen. Die beiden Methoden funktionieren unterschiedlich.
(Stellen Sie sich das in Ihrem Kopf vor)
get_cheese und set_cheese legen den Käse frei. putCheese () und takeCheese () halten den Käse versteckt und kümmern sich um die Verwaltung und geben dem Benutzer eine Möglichkeit, damit umzugehen. Der Beobachter sieht den Käse nicht, er sieht nur zwei Methoden, um ihn zu manipulieren.
quelle