EDIT: Ich habe diese Frage beantwortet, weil eine Reihe von Leuten, die das Programmieren lernen, diese Frage stellen, und die meisten Antworten sind technisch sehr kompetent, aber sie sind nicht so leicht zu verstehen, wenn man ein Neuling ist. Wir waren alle Neulinge, also dachte ich, ich versuche mich an einer anfängerfreundlicheren Antwort.
Die beiden wichtigsten davon sind Polymorphismus und Validierung. Selbst wenn es nur eine dumme Datenstruktur ist.
Nehmen wir an, wir haben diese einfache Klasse:
public class Bottle {
public int amountOfWaterMl;
public int capacityMl;
}
Eine sehr einfache Klasse, die angibt, wie viel Flüssigkeit sich in ihr befindet und welches Fassungsvermögen sie hat (in Millilitern).
Was passiert, wenn ich das tue:
Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;
Nun, Sie würden nicht erwarten, dass das funktioniert, oder? Sie wollen, dass es eine Art Sicherheitskontrolle gibt. Und schlimmer noch, was wäre, wenn ich nie die maximale Kapazität angegeben hätte? Oh je, wir haben ein Problem.
Aber es gibt noch ein weiteres 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 unterschiedlichen Kapazitäten und Flüssigkeitsmengen? Wenn wir nur eine Schnittstelle schaffen könnten, könnten wir den Rest unseres Programms diese Schnittstelle akzeptieren lassen, und Flaschen, Kanister und alles Mögliche würden einfach austauschbar funktionieren. Wäre das nicht besser? Da Schnittstellen Methoden erfordern, ist das auch eine gute Sache.
Das Ergebnis wäre dann etwa so:
public interface LiquidContainer {
public int getAmountMl();
public void setAmountMl(int amountMl);
public int getCapacityMl();
}
Großartig! Und jetzt ändern wir Bottle einfach in das hier:
public class Bottle extends LiquidContainer {
private int capacityMl;
private int amountFilledMl;
public Bottle(int capacityMl, int amountFilledMl) {
this.capacityMl = capacityMl;
this.amountFilledMl = amountFilledMl;
checkNotOverFlow();
}
public int getAmountMl() {
return amountFilledMl;
}
public void setAmountMl(int amountMl) {
this.amountFilled = amountMl;
checkNotOverFlow();
}
public int getCapacityMl() {
return capacityMl;
}
private void checkNotOverFlow() {
if(amountOfWaterMl > capacityMl) {
throw new BottleOverflowException();
}
}
Ich überlasse die Definition der BottleOverflowException dem Leser als Übung.
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 dieser Art von Dingen umgehen, kann ganz unterschiedlich sein. Sie können Flaschen haben, die ihren Zustand auf die Festplatte schreiben, wenn er sich ändert, oder Flaschen, die in SQL-Datenbanken oder GNU weiß was sonst noch speichern.
Und all diese können auf unterschiedliche Art und Weise mit verschiedenen Unglücken umgehen. Die Flasche prüft einfach, und wenn sie überläuft, löst sie eine RuntimeException aus. Aber das könnte der falsche Weg sein. (Es gibt eine nützliche Diskussion über die Fehlerbehandlung, aber ich halte sie hier absichtlich sehr einfach. In den Kommentaren werden die Leute wahrscheinlich auf die Schwächen dieses simplen Ansatzes hinweisen ;) )
Und ja, es scheint, dass wir von einer sehr einfachen Idee schnell zu viel besseren Antworten kommen.
Bitte beachten Sie auch, dass Sie das Fassungsvermögen einer Flasche nicht ändern können. Sie ist jetzt in Stein gemeißelt. Sie könnten dies mit einem int tun, indem Sie ihn für endgültig erklären. Aber wenn es sich um eine Liste handeln würde, könnte man sie leeren, neue Dinge hinzufügen und so weiter. Man kann den Zugriff nicht darauf beschränken, die Innereien zu berühren.
Es gibt noch eine dritte Sache, die noch nicht jeder angesprochen hat: Getter und Setter verwenden Methodenaufrufe. Das bedeutet, dass sie wie normale Methoden aussehen, wie überall sonst auch. Anstatt eine seltsame spezifische Syntax für DTOs und so zu haben, hat man überall das Gleiche.
8 Stimmen
@Dean J: D stackoverflow.com/search?q=getters+setters
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"
42 Stimmen
"Accessors sind böse", wenn Sie funktionalen Code oder unveränderliche Objekte schreiben. Wenn Sie zustandsbehaftete, veränderbare Objekte schreiben, dann sind sie ziemlich wichtig.
23 Stimmen
Erzählen, nicht fragen. pragprog.com/articles/tell-dont-ask
2 Stimmen
Mit Ausnahme von 6 und 8 würde ich es wagen zu sagen, dass keiner dieser Punkte in 99 % der Fälle zur Anwendung kommt. Dennoch würde ich gerne Java verwenden
String s = employee.name()
yemployee.name("oscar")
anstelle von getName() setName()1 Stimmen
@Oscar Reyes, ja, ich stimme zu, dass 6 und 8 meiner Erfahrung nach die beiden häufigsten sind. Das heißt, ich bevorzuge immer noch nicht mit der C#ish Syntax; mein alter Mann Gehirn wird verwirrt.
4 Stimmen
Ich bin überrascht, dass niemand über die Datensynchronisation spricht. Angenommen, Sie verwenden
public String foo;
es ist nicht fadensicher! Stattdessen können Sie definierenget
terset
ters mit Synchronisierungstechniken, um die Untreue von Daten zu vermeiden [d.h. ein anderer Thread, der das foo durcheinanderbringt]. Ich hielt es für erwähnenswert.3 Stimmen
@goldenparrot: Meistens ist die Synchronisierung einzelner Zugriffe auf ein Objekt viel zu ineffizient oder sogar anfällig für Synchronisierungsprobleme (wenn man mehrere Eigenschaften eines Objekts ändern muss sogleich ). IME, müssen Sie oft Operationen als Ganzes verpacken, die mehrere Zugriffe auf ein Objekt durchführen. Das kann nur durch Synchronisation auf der Seite der Benutzer eines Typs erreicht werden.
1 Stimmen
Fassen Sie Ihre Lieblingsstellen aus allen Antworten nicht in der Frage selbst zusammen. Dies ist eine Seite für Fragen und Antworten, kein Forum.
3 Stimmen
@ErikReppen was sollte ich lesen, um OOP überhaupt zu verstehen?
0 Stimmen
Es gibt auch das sehr wichtige Problem der gemeinsamen Nutzung von Code mit anderen, wenn Sie Objektfelder als Teile der externen Schnittstelle behandeln, die andere Leute nutzen können, dann könnte es unmöglich sein, das Feld in eine Funktion zu ändern, ohne Änderungen im Code anderer Leute zu zerstören.
0 Stimmen
@ErikReppen Danke für den Link, ich arbeite daran, zu verstehen, was OOP sein soll, aber es erweist sich als schwierig bei der Menge an Fehlinformationen, die im Umlauf sind. P.S. Ich finde auch, dass wikipedia eine der besten Quellen in vielen wissenschaftlichen Bereichen ist.
3 Stimmen
@TimoHuovinen es geht darum, nicht herausfinden zu müssen, welche von 500 Funktionen tatsächlich einen Wert ändert. Man macht einen Wert oder eine Reihe von Werten zu etwas, für das man verantwortlich ist, und nicht zu etwas, das man auf eine Param/Return-Achterbahn setzen kann. Vermeiden Sie Vanilla Getters/Setters und öffentliche Eigenschaften, und Sie werden oft feststellen, dass Sie innehalten und darüber nachdenken müssen, wie Sie Ihre Anwendung auf eine Art und Weise modellieren können, die in der Regel einfacher zu lesen, zu ändern, in großen Teilen wiederzuverwenden, zu debuggen ist und der Sie vertrauen können, ohne sie bis ins Mark zu testen. Java und C# haben OOP übertrieben und es dann aufgegeben, IMO.
1 Stimmen
In einem weiteren Artikel wird versucht, Leitlinien für die Verwendung von Gettern und Settern aufzustellen: Öffentliche oder private Mitgliedsvariablen? Das YAGNI-Prinzip leitet uns dazu an, erst dann Konstrukte hinzuzufügen, wenn wir wirklich wissen, dass wir sie brauchen werden.
0 Stimmen
Punkte 2, 3 (?), 4, 5 und 8: vorläufig ja. Die anderen: definitiv nein. Was spielt es für eine Rolle, ob Sie Python, C#, Ruby, Objective-C oder einen Esolang verwenden, wenn Ihr Code einfach, elegant und leicht wartbar/erweiterbar ist?
2 Stimmen
666 Upvotes scheinen kein Zufall zu sein
2 Stimmen
"Man kann leicht erkennen, dass Sie Python nicht benutzt haben" sollte eigentlich die Nr. 1 sein!
0 Stimmen
@Kaiserludi Könnten Sie erläutern, inwiefern das eine gute Sache ist?
0 Stimmen
@DeanJ Könnten Sie bitte die Nummer 10 erklären?
0 Stimmen
@Joshua: Das war nur ein Scherz, denn der Autor hat das eindeutig nicht ernst gemeint, als er es auf die Liste gesetzt hat.
2 Stimmen
11. T
1 Stimmen
Eine kürzlich gestellte Frage hat mich an einen weiteren Grund für Set-Methoden erinnert: die Möglichkeit, eine Änderung der Eigenschaft .