Getter,Setter - Konstruktor überflüssig?

  • Themenstarter Themenstarter blondesGift
  • Beginndatum Beginndatum
B

blondesGift

Gast
Hallo.

Ich habe bis jetzt noch nie mit getter und setter Methoden gearbeitet, muss dies nun aber machen.

Bis jetzt sah es immer so aus:

Java:
class Student
{
String Name;
int alter;

Student(String Name, int alter)
{
this.Name = Name;
this.alter = alter;
}

}

Wenn ich nun Getter und Setter Methoden verwenden will, dann muss ich die Klassenvariablen also Name und alter auf private setzen, oder?

Und dann als Beispiel für den Namen:

Java:
void setName(String Name)
{
this.Name = Name;
}

Java:
void getName()
{
return Name;
}

Aber das hat doch vorher mein Konstruktor gemacht.
Kann ich den dann weglassen?
Oder verstehe ich etwas falsch.

Ich hoffe Ihr könnt mir helfen 🙂
 
Beachte, dass eine void Methode keinen Rückgabewert hat.

Du kannst den Konstruktor theoretisch weglassen.

Da es in Java keinen Object INitializer gibt, müsste man nach dem erstellen jeden Setter einmal aufrufen.

Ich würde den Konstruktor lassen. ggf. kann man die Parameter des Konstruktors in die setter umleiten.

Gruß,

MArtin
 
Normalerweise versucht man den Scope (Geltungsbereich) einer Variable so klein wie möglich zu halten.

Also wäre bei dir

Java:
class Student
{
private String name;
private int alter;

Student(String name.....
}

Bei dir hat der Konstruktor die Werte gesetzt, aber was ist wenn du jetzt den Namen des Studenten ändern willst? Sind die Variabeln private geht das nicht mehr einfach mit dem punkt-Operator. Dafür gibts dann die setter/getter Methoden.

Anfangs wirste wahrscheinlich denken "wie unnötig viel aufwand", aber je komplexer etwas wird, umso notwendiger wirds. Außerdem kann man auch logik einbauen. z.b.

Java:
setAlter(int alter)
{
if(alter <= 0)
   this.alter = 1;
}

nur als Beispiel..
 
Wenn ich nun Getter und Setter Methoden verwenden will, dann muss ich die Klassenvariablen also Name und alter auf private setzen, oder?
Dir ist klar, was das Schlüsselwort
Code:
private
bewirkt? Es sollte unabhängig davon wie die Variable gesetzt wird
Code:
immer
benutz werden. Eines der grundlegenden Prinzipien der objektorientierten Programmierung ist Information Hiding. Das bedeutet, dass andere Klassen nicht wissen sollen, welche Variablen es hier gibt.
Aber das hat doch vorher mein Konstruktor gemacht.
Kann ich den dann weglassen?
Ja.

Diesmal scheint es ja nicht Deine Entscheidung zu sein, aber hier ist meine Daumenregel:
[TIPP]Wenn sich die Variable während der Laufzeit des Programms üblicher Weise nicht ändert, dann wird es über den Konstruktor gesetzt und
Code:
final
deklariert. (Wenn sie sich doch mal ändert wird halt ein neues Objekt erzeugt...)

Setter gibt es nur bei einem besonderen Klassentyp: den DTOs (DataTransferObject). Diese haben keine eigene Logik, nur Variablen und Getter-/Setter-Methoden. Aber auch bei denen bevorzuge ich die Konstruktorvariante.

In "normalen" Objekten sollte es keine Setter-Methoden geben. Interne Variablen dürfen nach OOP-Regeln nie direkt von außen geändert werden. Wenn sie sich ändern dann immer nur als Seiteneffekt von Methodenaufrufen. Z.B.: die aktuelle Geschwindigkeit eines Autos wird nicht über [STRIKE]
Code:
setGeschwindigkeit(int speed)
[/STRIKE] sondern:
Code:
beschleunige(int sekunden)
geändert. Der Aufrufer selbt muss dann beispielsweise nicht mehr wissen, ob es sich um einen Trabant oder einen Ferari handelt. Die Berechnung, wie schnell das Auto wird macht es selbst.[/TIPP]

bye
TT
 
> grundlegenden Prinzipien der objektorientierten Programmierung ist Information Hiding
> dürfen nach OOP-Regeln ...

Das muss man alles cum grano salis nehmen.
Wenn ich etwas aus der Hand gebe, dann sollten alle öffensicht sichtbaren Schnittstellen und Klassen diesem Prinzip folgen, damit man mal etwas ändern kann. Ähnliches gilt auch für allgemeine Bibliotheken, die man im eigenen Umfeld vielfältig einsetzt.

Java wurde entworfen für grafische Fenster-Umgebungen, Man benötigt dort zumindest eine Wiedereintrittsfähigkeit, welche technisch eben mit Objekten gelöst wurde. Wenn andere Aufgaben mit Java gelöst werden, dann ist das vollständige Verbergen von Informationen schädlich, es kann den Ciode verschlechtern.

Beispiel: Wenn ich eine Simulation des Wettergeschehens von FORTRAN nach Java transformieren wollte, dann würde sich die gesamte Simulation um die Matrizen der Zustandsgrößen drehen. Es ist sinnlos, diese zu verbergen, es geht ja um nix anderes. Ein getter ist insofern schädlich, als er eine unnötig aufgeblähte Notation erzeugt, mindestens ein zusätzliches Klamemrnpaar, meist noch ein get davor. Das lässt sich dann alles viel schlechter lesen, also schlechter warten. In C#ist das übrigens besser gelöst, da kann man ein get so schreiben, dass es sich nicht von einer Variablenreferenz unterscheidet. Auf Kosten der Komplexität der Sprache freilich.

Es gibt aber auch viel kleinere beispiele. Die OO-Logik erfordert an Stellen Objekte, weil da einfach nichts anderes sinnvoll reinpasst. Beispiel eine Hash-Tabelle. Das Objekt entspringt also nicht unbedingt dem Wunsch de Progarmmierers nach Kapselung, sondern der Programmlogik. Wenn ich dann kapsele, gilt dasselbe wie oben: Es liest sich schlechter, wird länger.
 
@piu58
Welcher wundersamen Quelle entnimmst du deine Behauptungen?

Was liest sich denn da besser?
Einfaches Beispiel.

Code:
irgendwas.neVariable = 0;
vs.
Code:
irgendwas.setVariable(0);

wo ist der Unterschied?
was wenn dir auffält, dass 0 für diese Variable nicht gültig ist?(angenommen, das passiert an 1000 Stellen im Programm so) ... richtig --> Mülleimer😳
 
Beispiel: Wenn ich eine Simulation des Wettergeschehens von FORTRAN nach Java transformieren wollte, dann würde sich die gesamte Simulation um die Matrizen der Zustandsgrößen drehen.

Kein besonders repräsentatives Beispiel für etwas, was der Durchschnitts-Erstsemestler so macht. Es gibt (und das weiß ich aus eigener Erfahrung) Fälle, in denen man durch "zu viel Abstraktion" Performance verliert, wo sie von entscheidendSTer Bedeutung ist. Es gibt solche Ausnahmefälle, wo man eine Methode braucht wie [c]float data[] = specialObject.getReferenceToInternalMatrixData();[/c] um auf diesen Daten dann effizient rechnen zu können, und wo ein [c]float dataN = generalObject.getMatrixData(n);[/c] die Performance in nicht akzeptablen Maße negativ beeinflusst.

Aber auch dort kann und sollte (!) man sich bemühen, diese hoch-implementierungsspezifischen Informationen NUR genau dort nach draußen sichtbar zu machen, wo es unbedingt sein muss. Information Hiding ist ein allgemeines Prinzip, das man beim Design von vornherein berücksichtigen sollte.

Der andere Punkt, der in den Zusammenhang dieses Threads passt, ist das Prinzip "Minimize Mutability". Besonders jetzt, wo concurrency immer wichtiger wird, sollte man den Zustandsraum eines Objektes möglichst klein halten. Ein Objekt sollte Funktionen erfüllen, und KEINE lose Ansammlung von Variablen sein, die mit gettern/settern pseudo-objekorientiert aufgebläht aber trotzdem nur von außen verändert wird. Bei jeder Klasse die praktische Eclipse-Funktion "Generate Getters and Setters" pauschal auf alle Fields anzuwenden ist einfach nur schlecht.

In diesem Sinne: Was soll "setName" bei einem Studenten? Wenn man mit der Brechstange argumentieren wollte, könnte man sagen, dass ein normaler Mensch ja auch seinen Namen ändern kann, gut.... Aber statt des Alters würde man vielleicht eher das Geburtsdatum speichern. Das ändert sich nämlich nie.

Das pauschale Verbannen von Settern, wie Timothy Truckle es propagiert, ist unrealistisch (aus verschiedenen Gründen - schon allein weil es zu viele Klassen in der Standard-API gibt, wo man ggf. erst nachträglich Informationen hineinreichen muss). Aber die damit verbundene Grundidee ist eben, die Veränderbarkeit von Objekten zu minimieren, und das ist nicht falsch.
 
> Welcher wundersamen Quelle entnimmst du deine Behauptungen?

Meiner eigenen Erfahrung.

> irgendwas.neVariable = 0; vs. irgendwas.setVariable(0);

Das ist set, das ist harmlos. Get ist schlimmer. Ich schrieb auch von get. Ein Beispiel aus meiner eigenen Praxis, eine Programmzeile: Wenn das Flag morris gesetzt ist, dann bringe an der Variable mH eine Korrektur an
Jetzt

Java:
if (morris) mH=iz.m678-5*Math.log10(iz.delta);

wäre

Java:
 if (morris) mH=iz.getM678()-5*Math.log10(iz.getDelta());

In dieser Zeile kommen nur zwei Werte vor. Es gibt Formeln, da kommen fünf bis zehn Werte vor (z.B. Messwerte aus einem Datensatz). Da wäre überall der Klammerwahnsinn, der durch die Einbettung in mathematische Funktionen nicht besser wird
 
Java:
if (morris) mH=iz.m678-5*Math.log10(iz.delta);
wäre
Java:
 if (morris) mH=iz.getM678()-5*Math.log10(iz.getDelta());
Aslo ich würde die Berechnung in die Klasse verschieben, aus der das Objekt
Code:
iz
kommt. Dann würde hier stehen:
Java:
 if (morris) mH= iz.calulateMH(5);
Und wenn
Code:
morris
auch noch 'ne Eigenschaft aus
Code:
iz
ist würde sogar das
Code:
if
wegfallen. Und dass wäre ein viel größerer Performance-Gewinn, als die umgehung des Getters jemals erreichen kann.

bye
TT
 
Da wir vom Design neuer Klassen reden ist das Beispiel etwas unpassend...

Wenn die Klassen nichts mit der Standard-API zu tun haben, ja. Von settern, die man "unfreiwillig" erbt mal abgesehen, kommt man aber auch bei neuen Klassen nicht immer um setter drumrum. Auch wenn man gegenseitige Abhängigkeiten zu vermeiden versucht oder auf DI zurückgreift. Aber um Sonderfälle und Details geht's hier wohl erstmal nicht. Man sollte sich nur genau überlegen, ob man einen setter braucht, und meistens ist die Antwort: Nein 😉
 
> Aslo ich würde die Berechnung in die Klasse verschieben, aus der das Objekt iz kommt. Dann würde hier stehen

Is ja nur ein Beispiel. Das Problem ist, dass man an solchen Berechnungen oft Daten der Instanzen mehrerer Objekte braucht. Man kann eines eliminieren, wenn man die Berechnung dorthin verschiebt. Das Grundproblem bleibt.
 
> Aslo ich würde die Berechnung in die Klasse verschieben, aus der das Objekt iz kommt. Dann würde hier stehen

Is ja nur ein Beispiel. Das Problem ist, dass man an solchen Berechnungen oft Daten der Instanzen mehrerer Objekte braucht.
[EDIT][STRIKE]Das ist das Paradebeispiel für den Vorteil abstrakter Klasssen...[/STRIKE]Gut, dann komme ich nur über Getter an die Daten, das stimmt.[/EDIT]
Man kann eines eliminieren, wenn man die Berechnung dorthin verschiebt. Das Grundproblem bleibt.
[EDIT][STRIKE]wieso, innerhalb einer Klasse brauche ich doch keine Getter/setter.

Aber wenn die OO zu schwierig ist mach den Kram doch in Perl....[/STRIKE][/EDIT]

bye
TT
 
Zuletzt bearbeitet:
@Timothy: es gibt Algorithmen, die hat irgendjemand mal in einer Nicht-OOP Sprache wie Fortran oder C in Code gegossen und sowas portiert man besser ohne grössere Schnörkel nach Java - auch wenn das Ergebnis gruselig aussieht. Man kann danach natürlich Refactoring in Richtung OOP betreiben, damit verliert man aber recht schnell den Bezug zur Orginalimplementation die unter Umständen fehlerbereinigt/verbessert wird. Relativ einfache Beispiele sind en/decoding von JPEG, MP3 etc.. wo die Java-Portierungen sich eng an den C-Source halten.

Wenn Du natürlich die Algorithmen alle im Kopf hast, kannst Du das natürlich gemäss der reinen OOP-Lehre schreiben.

Bernd
 
@Timothy: es gibt Algorithmen, die hat irgendjemand mal in einer Nicht-OOP Sprache wie Fortran oder C in Code gegossen und sowas portiert man besser ohne grössere Schnörkel nach Java - auch wenn das Ergebnis gruselig aussieht.
Das ist richtig und dem will ich auch nicht widersprechen. Ich finde nur den Schluß, den piu58 daraus zog, dass Information Hiding generell hinderlich ist und zu vermeiden sei, nicht zulässig.

bye
TT
 
Das ist richtig und dem will ich auch nicht widersprechen. Ich finde nur den Schluß, den piu58 daraus zog, dass Information Hiding generell hinderlich ist und zu vermeiden sei, nicht zulässig.

Ich habe eine vage Vorstellung davon, in welcher Ecke Uwe arbeitet und da ist "Information Hiding" durchaus "generell hinderlich" weil da nur fette Objekte mit allen möglichen Matritzen durch die Gegend geschoben werden.

Auch wenn man als Java-Entwickler immer glaubt, mit dem feinen Zahnarztbohrer unterwegs zu sein gibt es immer noch die Aussenwelt die manchmal nach einem dicken Hammer schreit 🙂

Bernd
 
Ich habe eine vage Vorstellung davon, in welcher Ecke Uwe arbeitet und da ist "Information Hiding" durchaus "generell hinderlich" weil da nur fette Objekte mit allen möglichen Matritzen durch die Gegend geschoben werden.
Dann muss man sich aber auch die Frage gefallen lassen, ob eine OO-Sprache die richtige Wahl ist...

Auch wenn man als Java-Entwickler immer glaubt, mit dem feinen Zahnarztbohrer unterwegs zu sein gibt es immer noch die Aussenwelt die manchmal nach einem dicken Hammer schreit 🙂
Ja, und wenn man dann richtig gut mit dem Hammer umgehen kann ist jedes Problem ein Nagel...
😉

bye
TT
 
> Weil man ganz gerne drumherum mit OO weiterentwickeln möchte?

Es gibt noch andere Gründe. Wenn mein einen ALgorithmus formuliert hat, der eine SImulation ausführt, dann ist das sozusagen für die Ewigkeit. Es hat mit dem konkreten Stand der Computertechnik wenig zu tun, wenigstens sollte es das. Welche Sprache soll man da nehmen? Schwierig.
Vor 20 Jahren habe ich Pascal genommen, das war noch vor Windows. Hat an Verbreitung extrem eingebüßt. Fortran könnte man freilich immer nehmen, aber dort eine Visualisierung zu basten, verlangt praktisch nach einer zweiten Sprache, zweiten Entwicklungsumgebung usw. Außerdem ist das selbst mir zu altertümlich.
Java hat den Vorteil der Plattformunabhängigkeit. Damit entwickelt man nicht für ein konkretes Betriebssystem (à la xxx für C64).
Die OO-Entwurfsprinzipien sind auch für deratige Probleme extrem nützlich. Was ich aber anmerken möchte, ist dass die hier innig vertretenen OO-Regeln nicht immer sklavisch angewwandt werden sollten. Die Formulierung muss problemnah sein. Formeln, die zusammengehören, sollten auch untereinander stehen und nicht als Methoden in verschiedene Objkete verteilt. Dazu muss man Daten aus den Objekten lesen, und das sollte den Lesefluss des Programmes (der schließlich einen in Code dargestellten Algorithmus darstellt) so wenig wie möglich behindern.

Noch paar Worte zu dem was ich mache: Ich arbeite auf zwei Gebieten, Astronomie und Medizin. In der Astronomie simuliere ich die Physik der Kometen, also was in den Gashüllen dort passiert und wie man wichtige Kenngrößen aus irdischen Beobachtungen ableiten kann. Medizinisch simuliere ich die physiologischen Funktionsstörungen schwerkranker Patienten aus Messwerten und gebe Prognosen / Empfehlungen für die Therapie ab.
 
Meine Erfahrung ist, dass man (FAST) immer besser dran ist

1. alle Member-Variablen grundsätzlich
Code:
private
zu machen.

2. immer einen Konstruktor zu schreiben, der möglichst viele Members korrekt initialisiert: kein Client will bei der Erzeugung noch zusätzlich 10 setter aufrufen, da passieren nur Fehler...

Das hat keine Nachteile, vom minimalen Schreibaufwand für die getter/setter (wird heute eh von der IDE gemacht) mal abgesehen. Die Vorteile in Bezug auf spätere Modifikationen, Sicherheit, Wartbarkeit überwiegen bei weitem.
 
Meine Erfahrung ist, dass man (FAST) immer besser dran ist

1. alle Member-Variablen grundsätzlich
Code:
private
zu machen.

Wie sind Deine Erfahrungen mit statischen Konfigurationsklassen wo zb. irgendwelche Programmpfade oder Benutzereinstellungen abgelegt werden? Da bin ich schon lange am überlegen, ob ich da doch getter/setter einführe - was eigentlich nur Overhead ist da nie eine Prüfung der Daten stattfindet.

Bernd
 
Unabhängig von der Frage, ob es solche Klassen überhaupt geben sollte (ich habe auch solche Sachen, aber einem OO-Nazi würde es da wohl kalt den Rücken runterlaufen) : Gerade da lohnt sich das IMHO. Wenn man statt
Java:
class Config
{
    public static final String ROOT_PATH = "C:/Bla/";
}
eine Methode anbietet, kann man sich den Path dort (ggf. für Tests oder abhängig vom user.dir oder anderen Dingen) zusammenbauen.
 
Unabhängig von der Frage, ob es solche Klassen überhaupt geben sollte

Hm.

Konfigurationsdaten dürfen vom Programm nur gelesen werden, die Modifikation erfolgt ausschliesslich über die GUI bzw. durch laden aus der Konfigurationsdatei.

In letzter Konsequenz müsste man das alles in einer Klasse zusammenfassen oder eine Klasse "Config" haben wo die setter "protected void setVal(...)" sind und die GUI dann "ConfigGUI extends Config" drunterhängt - was aber meisstens nicht geht da viele GUIs von einer Frameworkklasse erben (parallelvererbung haben wir ja nicht).

Das Konfigurationsobjekt muss dann überall durchgereicht werden. Klingt irgendwie aufregend 🙂

Wie macht man es als "OO-Nazi" richtig?

Bernd
 
Nunja, die Kritik daran hat aber zumindest eine mögliche Rechtfertigung. Ich selbst durfte mich mit einem System rumschlagen, wo zig Einstellungen in einer Config-Klasse gespeichert waren, die da aber definitiv nicht hingehörten. Insbesondere waren das auch nicht-finale Eigenschaften. Mann, war das praktisch, da konnte man von überall drauf zugreifen 🙂 Bis auf einmal die Notwendigkeit der "Observierung" (im Sinne von MVC) dazukam. Spätestens, wenn es zwei ("unabhängige") GUI-Components gibt, die die gleiche (oder abhängige) Eigenschaften verändern, oder irgendjemand sonstwie über eine Änderung so einer Eigenschaft informiert werden muss, kommt man damit in die Hölle, wenn man nicht ALLES schön sauber in ein Modell gepackt hat, das bei jeder Änderung Listener benachrichtigen kann.
 
Wie sind Deine Erfahrungen mit statischen Konfigurationsklassen wo zb. irgendwelche Programmpfade oder Benutzereinstellungen abgelegt werden? Da bin ich schon lange am überlegen, ob ich da doch getter/setter einführe - was eigentlich nur Overhead ist da nie eine Prüfung der Daten stattfindet.

Bernd
Verwende RessourceBundles, Properties oder Datenbanken. Wobei man in der Datenbank natürlich nicht die Zugangsdaten ablegen kann 🙂 Dann stecke ich das oft beim Einlesen in Enums oder Maps.
 

Zurück
Oben