# immer Setter-Methoden verwenden?



## nossek (8. Aug 2010)

Hallo,

in den Lehrbuchbeispielen sehen Konstruktoren meist so aus:

```
public Person (String name){
    this.name = name;
}
```
Sollte man es (vorausgesetzt das jeweilige Attribut ist nicht final) nicht grundsätzlich besser so machen:

```
public Person (String name){
    setName(name);
}
```
Der zweite Fall hat den Vorteil, daß das Attribut wirklich nur an einer Stelle (also im Setter) verändert werden kann. Wenn man später auf die Idee kommt, irgendwelche Überprüfungen hinzuzufügen (wat weiß ich, ob der Name Ziffern enthält und das aber nicht erlaubt ist...), das lässt sich das ganz flott leicht implementieren...

Was meint ihr?


----------



## Tobias (8. Aug 2010)

Grundsätzlich richtig, sofern der Setter nicht durch Subklassen überschrieben werden kann (als final  oder private deklariert ist). Ansonsten wird der Setter aus der Subklasse aufgerufen, bevor die Subklasse vollständig initialisiert wurde, was zu schwierig zu findenden Fehlern führen kann.


----------



## nossek (8. Aug 2010)

:grübel:
In dem Fall, daß 
- man die Möglichkeit haben möchte, eine Setter-Methode in abgeleiteten Klassen zu überschreiben (was wohl nicht so ungewöhnlich ist) 
und
- beim Iniititalisieren bzw. Ändern des Attributes weitere Aktionen (zB. Parameterprüfung) passieren sollen:
dann kommen wir um doppelten Code nicht herum? Dann müsste ja die Parameteprüfung im Konstruktor und im Setter stehen. ???


----------



## Tobias (8. Aug 2010)

Oder in einer privaten Methode, die sowohl vom Setter als auch vom Konstruktor aufgerufen wird. Das wird zwar nur in wenigen Java-Projekten finden, aber grundsätzlich wäre das der einzig richtige Weg.


----------



## nossek (8. Aug 2010)

verstehe!
Wenn aber die Parameterprüfung auch übrschrieben werden soll, dann hätte man wohl wieder dasselbe Problem?
Naja, irgendwie habe ich das Gefühl, ich konstruiere hier Probleme, die in der Praxis kaum auftauchen!
Schätze mal, bei einer vernünftig entworfenen Klassenhierarchie sollte man das Problem nicht haben.

Vielen Dank jedenfalls!


----------



## Ark (8. Aug 2010)

Ich handhabe das ja üblicherweise so:

Wenn mindestens eine finale Instanzvariable existiert, die ihren Wert von einem Parameter eines Konstruktors bekommen muss, so darf der Konstruktor nur Parameter zur Initialisierung dieser finalen Instanzvariablen besitzen. Sonstige Instanzvariablen dürfen von außen nur später mittels Settern festgelegt werden. (Das führt dazu, dass Konstruktoren in diesem Fall niemals Setter aufrufen müssen/können, weil es die entsprechenden Setter gar nicht gibt.)
Wenn die Klasse final ist und mehrere Instanzvariablen nur gemeinsam gesetzt werden dürfen, diese aber nicht final sind, dann existiert eine passende öffentliche reset()-Methode, der sich auch der passende Konstruktor bedient. (Dies ähnelt Tobias' Vorschlag.)
Wenn quasi zu beliebigen Zeitpunkten Werte von Instanzvariablen geändert werden können, ruft der Konstruktor die entsprechenden Setter auf, wenn die Setter final sind.
Da bei mir eh fast alle Klassen final sind und direkt von Object abgeleitet werden, treten andere Fälle kaum auf. 

Ark


----------



## nossek (8. Aug 2010)

Hallo Ark, danke für Deine Antwort, die allerdings meinen Horizont übersteigt :bahnhof:

Hoffe bald Verständnisfragen stellen zu können.


----------



## Ark (8. Aug 2010)

Okay, da meine Erklärungen vielleicht doch etwas zu abstrakt sind, hier ein paar FooBars, zunächst zum ersten Fall:


```
public class Foo{

	private final int bar;
	private int moreBar;
	
	// gut:
	public Foo(int bar){
		this.bar = bar;
		this.moreBar = 1; // okay
	}
	
	// schlecht:
	public Foo(int bar,int moreBar /* nicht okay */){
		this.bar = bar;
		// moreBar sollte hier nicht über einen Parameter gesetzt werden.
		this.moreBar = moreBar; // nicht okay
		// Besser: setMoreBar() von außen aufrufen lassen.
		// Allgemein: Wenn man finale Instanzvariablen (wie hier bar) über
		// Parameter des Konstruktors festlegen muss, dann sollte der
		// Konstruktor keine Parameter haben, um nicht-finale Instanzvariablen
		// zu initialisieren.
		// Anders ausgedrückt: Wenn "final fields" über Parameter, dann
		// Parameter auch nur für "final fields".
	}
	
	public void setMoreBar(int moreBar){
		this.moreBar = moreBar;
	}
}
```
Nun zu Fall zwei:

```
public final class Foo{ // das final hier ist sehr anzuraten

	private int bar1;
	private int bar2;
	private int otherBar;
	
	public Foo(int bar1,int bar2){
		reset(bar1,bar2);
	}

	public void reset(int bar1,int bar2){
		this.bar1 = bar1;
		this.bar2 = bar2;
		// Diese reset()-Methode erlaubt es, auf Wunsch dieses Objekt
		// wiederzuverwenden. Um Fehler beim Recyclen zu vermeiden, sollten
		// hier alle notwendigen Werte abgefragt werden und es sonst keine
		// anderen Stellen geben, an denen (hier im Beispiel) bar1 und bar2
		// gesetzt werden. So braucht man auch keine Setter dafür.
	}
}
```
Und der letzte Fall:

```
public class Foo{

	private int bar1;
	private int bar2;
	private int otherBar;
	
	public Foo(int bar1,int bar2){
		setBar1(bar1);
		setBar2(bar2);
		// In solchen Fällen ist der Konstruktor vor allem der Bequemlichkeit
		// geschuldet. Man hätte auch die Setter später selbst aufrufen können.
		// Wie man sieht, sollte man Vererbung aber nur mit Bedacht einsetzen,
		// weil so was schnell zu Problemen führen kann. Die Setter sind hier
		// final, noch besser wäre es natürlich, wenn die Klasse komplett final
		// wäre.
	}

	public final void setBar1(int bar1){
		this.bar1 = bar1;
	}
	
	public final void setBar2(int bar2){
		this.bar2 = bar2;
	}
}
```
Ich hoffe, es ist nun verständlicher.

Ark


----------



## Marco13 (8. Aug 2010)

@Ark: Du hast jetzt beschrieben, wie die Regeln sind, an die du dich üblicherweise hältst. Aber ich (bin antiautoritär erzogen  und ) würde dann erstmal fragen, wie diese Regeln begründet sind. Sie wirken zumindest sehr spezifisch und ausgefeilt und schwer zu überprüfen, und u.U. auch schwer einzuhalten: Angenommen man hat schon zwei, drei Konstruktoren, und jetzt kommt in die Klasse auf einmal noch eine Variable, die final sein könnte/sollte - dann würde auf einmal die Regel greifen:
_Wenn mindestens eine finale Instanzvariable existiert, die ihren Wert von einem Parameter eines Konstruktors bekommen muss, so darf der Konstruktor nur Parameter zur Initialisierung dieser finalen Instanzvariablen besitzen._
Die Abhilfen (die anderen Konstruktoren wegwerfen - oder "die Variable einfach nicht-final machen"  - stelle ich mir da schwierig vor).


Teilweise ist das verwandt mit diesem Thread: Ich finde, man sollte _eigentlich_ die setter verwenden, aber das macht man eben üblicherweise nicht (im Zweifelsfall ist die Begründung, dass Java eben nicht das UAP einhält).


----------



## nossek (8. Aug 2010)

Danke Ark für die ausführlichen Beispiele!

Allerdings muß ich mich Marco13 anschliessen: Du erklärst welche Regeln Du Dir überlegt hast, aber ich verstehe immer noch nicht so recht was sie verhindern sollen.

zB.: Wenn zum Zeitpunkt eines Konstruktoraufrufs meinetwegen 3 Parameter bereits bekannt sein könnten, von denen einer final ist und zwei nicht, wo ist den eigentlich das Problem wenn ich einen Konstruktor schreibe, dem diese drei übergeben werden?

Sorry daß Du Dir so eine Mühe gibst und ich es trotzdem nicht verstehe! 

@Marco13


> Teilweise ist das verwandt mit diesem Thread:


Wow, den habe ich mir grad durchgelesen, äußerst interessant! Ich finde die Argumente aller Beteiligten (soweit ich sie verstehe) einsichtig, enthalte mich aufgrund mangelnder Erfahrung eines eigenen Urteils und bilanziere für mich zunächst einmal: Es gibt viele nützliche Regeln, aufpassen und denken können sie einem nicht abnehmen...


----------



## Ark (8. Aug 2010)

Marco13 hat gesagt.:


> Aber ich (bin antiautoritär erzogen  und ) würde dann erstmal fragen, wie diese Regeln begründet sind. Sie wirken zumindest sehr spezifisch und ausgefeilt und schwer zu überprüfen, und u.U. auch schwer einzuhalten: Angenommen man hat schon zwei, drei Konstruktoren, und jetzt kommt in die Klasse auf einmal noch eine Variable, die final sein könnte/sollte - dann würde auf einmal die Regel greifen:
> _Wenn mindestens eine finale Instanzvariable existiert, die ihren Wert von einem Parameter eines Konstruktors bekommen muss, so darf der Konstruktor nur Parameter zur Initialisierung dieser finalen Instanzvariablen besitzen._
> Die Abhilfen (die anderen Konstruktoren wegwerfen - oder "die Variable einfach nicht-final machen"  - stelle ich mir da schwierig vor).


Ich erkläre meine Überlegungen dazu gerne, und sollte sich am Ende herausstellen, dass ich eigentlich dumm wie Brot bin, habe ich wenigstens was gelernt. 

Diese Regeln dienen mir selbst vorrangig als Muster für Klassen und haben sich bei mir so herauskristallisiert, weil mich das gleiche Problem nervte wie den TO. Diese Regeln sind nicht in Stein gemeißelt, geben mir aber eine gute Orientierung und sorgen für Übersichtlichkeit.

*Zu Fall 1:* Man kann sich viel Ärger ersparen, wenn man die final fields schon beim Entwurf ein für allemal festlegt (zumindest wäre es erstrebenswert). hashCode(), equals() und ggf. compareTo() lassen sich so leicht implementieren bzw. generieren und funktionieren im Zusammenhang mit Collections dann auch wie erwartet.

Dieser Fall entstand, wie vielleicht schon zu erahnen war, in Anlehnung an die Idee der unveränderlichen (immutable) Objekte. Der Konstruktor bekommt damit ausschließlich(!) die Aufgabe, die unveränderlichen bzw. zur Identifizierung in Collections notwendigen final fields zu initialisieren. Würden die Parameter für non-final fields neben denen für final fields auftauchen, erscheinen sie als "wichtiger", als sie in dem Augenblick sind. ("Wichtig" bzw. "unwichtig" bezieht sich auf den Zeitpunkt, an dem Werte zur Verfügung stehen müssen. Non-final fields können auch später festgelegt werden, sie sind also vergleichsweise unwichtig.)

Der Witz an der Sache ist ja, dass ein Konstruktor nur aufgerufen werden kann, wenn für _alle_ Parameter brauchbare Werte existieren. Wenn also der Konstruktor final fields initialisieren muss, wäre ohne Einhaltung dieser Regel der Aufrufer möglicherweise dazu verdonnert, Werte für non-final fields anzugeben, obwohl diese noch gar nicht vorliegen (weil z.B. ein anderes Objekt erst sinnvolle Werte dafür liefern kann, _nachdem_ es von unserem gerade erzeugten Foo erfahren hat).

Zwar gibt es so etwas wie Überladung, aber ich finde, es kann schnell unübersichtlich werden, wenn in einer einzigen Parameterliste "wichtige" und "unwichtige" Parameter nebeneinander auftauchen.

Eindämmen könnte man das Problem damit, dass grundsätzlich _alle_ von außen festlegbaren final fields entsprechende Parameter bekommen. Dann wäre ersichtlich, dass Parameter, die nicht in allen Konstruktoren auftauchen, nur für non-final fields da sind. Daraus ergibt sich aber wieder ein Problem: Wenn es viele final fields gibt, weisen die Konstruktoren entsprechend lange Parameterlisten auf (siehe oben das Problem: es müssen genügend Werte vorliegen!), und das dient nicht gerade der Übersichtlichkeit.

Wenn nun tatsächlich der Fall eintreten sollte, dass final fields hinzukommen oder entfernt werden (was schon schlimm genug sein dürfte), müssten _alle_ Parameterlisten der Konstruktoren wieder angepasst werden, was dazu führte, dass kein einziger Konstruktoraufruf mehr stimmen würde. Hier als "Lösung" wieder zu überladen, birgt zum einen das Risiko, schneller als sonst Kollisionen wegen plötzlich gleich aussehender Signaturen heraufzubeschwören. Zum anderen hat es zur Folge, dass dann Konstruktoren mit vielen quasi-optionalen Parametern zur Verfügung stehen, von denen _einige_ "wichtig" und _einige_ wieder "unwichtig" sind. Zumindest ich würde dann nicht mehr wirklich durchblicken, wie ich welchen Parameter bewerten muss.

Deshalb lautet meine Devise: Wenn ein Konstruktor Parameter für final fields bereitstellt, dann sollten alle Konstruktoren auch _nur_ Parameter für final fields haben. Das sagt mir dann als Aufrufer, dass alle Parameter gleich "wichtig" sind. Und dann klappt das auch wieder mit dem Überladen. 

Zu *Fall 2* und *Fall 3* habe ich gerade keine Lust.  Die Kurzfassung: Fall 2 ist eine Abschwächung von Fall 1 (es würde sich dann eher um "semi-final" fields handeln) mit dem Hintergrund, den bereits für ein Objekt reservierten Speicher wiederverwenden zu können. Fall 3 hat mit den anderen nicht mehr viel zu tun. Schreibzugriffe auf fields durch einen Konstruktor erfolgen eben genauso, als hätte man manuell die Setter aufgerufen, wodurch Schreibzugriffe von außen vereinheitlicht sind (das ist bei den anderen Fällen bereits implizit so).

Ich hoffe, das ist jetzt etwas klarer geworden. 

Ark


----------



## mvitz (8. Aug 2010)

Was ich an dieser Zusammenfassung kritisieren würde ist folgendes:

Der Konstruktor dient dazu, ein Objekt mit einem gültigen Zustand zu erstellen. Wenn nun z.B. ein Kunde neu erstellt wird, dann kann es ja per Definition sein, dass ein Kunde einen Namen haben muss, diesen aber im Nachhinein noch ändern darf.
Insofern kann das Feld name nicht final sein, muss aber trotzdem mit im Konstruktor gesetzt werden, da das Objekt sonst in keinem gültigen Zustand ist.

Dieser Fall würde somit deiner Regelung schon widersprechen.


----------



## Ark (8. Aug 2010)

mvitz hat gesagt.:


> Der Konstruktor dient dazu, ein Objekt mit einem gültigen Zustand zu erstellen. Wenn nun z.B. ein Kunde neu erstellt wird, dann kann es ja per Definition sein, dass ein Kunde einen Namen haben muss, diesen aber im Nachhinein noch ändern darf.
> Insofern kann das Feld name nicht final sein, muss aber trotzdem mit im Konstruktor gesetzt werden, da das Objekt sonst in keinem gültigen Zustand ist.


Hm, stimmt, das könnte eng werden.  So, wie du es gerade darstellst, ist das aber eher der dritte Fall, passt also problemlos.

Vielen Dank für die Kritik, ich freue mich schon auf mehr. 

Ark


----------



## faetzminator (8. Aug 2010)

@Ark:
Nunja, abgesehen davon, dass ich nicht finale Variablen ebenfalls mit überladen des Konstruktors zu setzen erlauben würde - immerhin rufe ich nach einem Konstruktoraufruf nicht unbedingt viele Setter auf -, gebe ich dir da recht. Aber irgendwie verwende ich im Allgemeinen zu wenig final, hab ich das Gefühl.


----------



## nossek (8. Aug 2010)

[offtopic] Dieses Forum ist ja geradezu vorbildlich.:toll: Man kriegt immer schnell geholfen und die Streitkultur ist vom feinsten! Auch in dem Thread den Marco13 weiter oben verlinkt hat... Aus den fachlichen Fragen hier halte ich mich mal raus, verfolge die Disskussion aber mit Interesse.[/offtopic]


----------



## kirax (9. Aug 2010)

Also Setter und Getter final zu machen ist ein bisschen gegen OOP. Das ist eigentlich nur sinnvoll, wenn die Klasse selbst auch final ist, was man nur machen sollte, wenn man sich absolut sicher ist, dass es keinen Sinn macht, Unterklassen davon zu bilden.

Generell sollte man sich angewöhnen, in allen public Methoden/Konstruktoren die übergebenen Parameter auf Gültigkeit zu prüfen und ggf. eine IAE zu werfen:

```
public double divide(int dividend, int divisor) {
  if (divisor == 0) {
    throw new IllegalArgumentException("divisor must be != 0");
  }
  return ((double) dividend) / divisor;
}

public void <T> addToList(List<T> list, T item) {
  if (item == null) {
    throw new IllegalArgumentException();
  }
  list.add(item);
}

public Konstruktor(int v1, String v2) {
  if (v2 == null || v2.length() == 0) {
    throw new IllegalArgumentException();
  }
  this.v1 = v1;
  this.v2 = v2.substring(0, 1);
}
```

Diese Praxis beugt Aufrufen "aus Versehen" aus einem Kontext, wo die Variablen nicht geprüft sind, vor, die sonst eine unvorhergesehene Exception werfen. Die Beispiele sind jetzt zwar etwas hergeholt, aber das muss nur ein bisschen komplexer werden, und schon blickt kaum noch jemand durch. Dann fliegt an irgend einer Stelle z.B. eine ArrayStoreException, bloß weil 20 Zeilen oben drüber eine Variable null war, was keiner merkt, da dieser Parameter nicht geprüft wurde.

Faustregel: Bei publics Exception werfen, wenn was nicht stimmt, bei privates per Assertion absichern:


```
private divide(int dividend, int divisor) {
  assert divisor != 0;
  return ((double) dividend) / divisor;
}
```

Assertions haben den Vorteil, dass sie zur Laufzeit im Produktiven deaktiviert sind. Startet man das Programm mit

```
java -ea MeinProg
```
Fliegt im Fall, dass divisor == 0 ist beim Aufruf, ein AssertionError. Gut in der Entwicklungsphase, um sicherzugehen, nur "sichere" Aufrufe zu machen.


----------



## bygones (10. Aug 2010)

kirax hat gesagt.:


> Also Setter und Getter final zu machen ist ein bisschen gegen OOP. Das ist eigentlich nur sinnvoll, wenn die Klasse selbst auch final ist, was man nur machen sollte, wenn man sich absolut sicher ist, dass es keinen Sinn macht, Unterklassen davon zu bilden.


die Aussage ist leider schon falsch... man sollte eine Klasse IMMER final machen, ausser man weiss, dass sie fuer die Vererbung relevant ist. Vererbung ist leider ein völlig überschätztes und missbrauchtes Konstrukt in OOP - weiterhin ist es einfacher eine finale Klasse für Vererbung zu öffnen, als im Nachhinein eine Klasse aus der Vererbung rauszunehmen.



kirax hat gesagt.:


> Generell sollte man sich angewöhnen, in allen public Methoden/Konstruktoren die übergebenen Parameter auf Gültigkeit zu prüfen und ggf. eine IAE zu werfen:


wenn die Gültigkeit von nöten ist ja - und vor allem wenn man dies über die API auch kommuniziert.

Ansonsten bin ich gegen das Konstruieren eines Objektes, welches dann der Aufrufer noch per setter "vollständig" machen muss. Nach dem Aufruf einer Factory Methode bzw eines Konstruktors sollte man eine gültiges Objekt haben. Daraus resultiert auch dass instanzvariablen ebenso per se final gesetzt werden sollten.

Allgemein würde ich setters/getters insgesamt versuchen so weit wie möglich zu vermeiden, erst wenn sie wirklich gebraucht werden sie dann auch zu erstellen. Und selbst dann ist drauf zu achten was man preisgibt bzw übernimmt (bei getters wg Immunibilität der Variablen bzw Preisgeben von Interna achten) (bei setters allgemein wg Immunibilität achten)

Zur eigentlichen Frage:
"immer setters verwenden" -> nein
setters im Konstruktor aufrufen -> halte ich für unsinnig wenn es sich um eine simple Variablenzuweisung handelt - wie gesagt, sehe wenige Gründe warum die Instanzvar. nicht final ist und warum man unbedingt immer von aussen sie manipulieren muss... ergo setz ich lieber sie direkt im konstruktor als über einen weiteren (wenn auch privaten) setter


----------



## maki (10. Aug 2010)

> Assertions haben den Vorteil, dass sie zur Laufzeit im Produktiven deaktiviert sind. Startet man das Programm mit


Unittests sind den Java Assertions zu bevorzugen.


----------



## Jango (10. Aug 2010)

Mal ne Frage...
Gibt es überhaupt setter/getter in java? Oder muss man die Methoden nur so nennen, damit sie hinterher so aussehen?


----------



## bygones (10. Aug 2010)

Jango hat gesagt.:


> Mal ne Frage...
> Gibt es überhaupt setter/getter in java? Oder muss man die Methoden nur so nennen, damit sie hinterher so aussehen?


oeh wie ? *kopfkratz*


----------



## Marco13 (10. Aug 2010)

Es sind "ganz normale Methoden", die einfach mit set/get anfangen, und nicht mehr machen (sollten) als die entsprechenden ... "Dinger" in C#. (Dort gibt es ja diese "impliziten" set/get-Methoden, was ein bißchen näher am UAP ist...)


----------



## Jango (10. Aug 2010)

bygones hat gesagt.:


> oeh wie ? *kopfkratz*



Ich präzisieren es:

Gibt es ein Konstrukt in Java, welches die API dafür vorsieht?

ups - Marcos Beitrag net gelesen.
Kommentar dazu:


----------



## bygones (10. Aug 2010)

Jango hat gesagt.:


> Ich präzisieren es:
> 
> Gibt es ein Konstrukt in Java, welches die API dafür vorsieht?
> 
> ...


ah - das versteh ich nun auch 

jo.. siehe Marco


----------



## kirax (10. Aug 2010)

maki hat gesagt.:


> Unittests sind den Java Assertions zu bevorzugen.



Sicher - ausschließlich Assertions zum Testen zu benutzen reicht nicht. Aber so eine Assertion kann einfach schneller "runtergeschrieben" werden, als ein Unittest. Und direkt mit testgetriebener Entwicklung (also Test vor Code) anzufangen ist auch nicht jedermanns Sache.

Assertions behindern Unittests ja nicht.


----------



## maki (10. Aug 2010)

> ber so eine Assertion kann einfach schneller "runtergeschrieben" werden, als ein Unittest.


Wenn man seinen Code & Testcode richtig organisiert hat, kommt man vielleicht an das Idealziel: Isolierte Unittests brauchen 10-15% der Zeit, die man zum schreiben des zu testenden Codes braucht, 



> Assertions behindern Unittests ja nicht.


Unittests machen Assertions meist überflüssig, wichtiger ist, dass Unittests viel mehr leisten.

Zuim Thema TDD verweise ich auf bygones Signatur


----------



## sign (12. Aug 2010)

```
public Person (String name){
    this.name = name;
}
```

so hab ich es in der Schule gelernt. Getter und Setter verwendet man um Variablen in einem Objekt von  außen zu ändern. Die Variablen sind private damit sie nach außen nicht sichtbar sind. 
[JAVA=42]private name =  "N.N";[/code] Man soll sie nicht public machen und über "Objektinstanz.name = name" von außen ändern/aufrufen. Getter und Setter sind public.

[JAVA=42]
 public Person (String name){
    setName(name);  // es macht doch keine Sinn einen public setter von innen aufzurfen.
    doSomething(name) // warum nicht, ist dann aber kein setter. Wobei doSomething(name) private ist.
    //oder do something mit der Variable im Konstruktor...
}
[/code]

[JAVA=42]
public void setName(String name){
    this.name = name;
}
[/code]


----------



## Marco13 (12. Aug 2010)

> Getter und Setter sind public.



Pauschale Aussagen sind IMMER falsch  Es gibt oft genug den Fall, dass man eine Eigenschaft
- nur für abgeleitete Klassen oder Klassen des gleichen Packages lesbar machen will 
- für alle lesbar, aber nur für abgeleitete Klassen oder Klassen des gleichen Packages schreibbar machen will
- sie überhaupt NUR lesbar machen will (immutable objekte)
usw.





> ```
> setName(name);  // es macht doch keine Sinn einen public setter von innen aufzurfen.
> ```



Doch, wenn er mehr macht, als nur den Namen zu setzen:

```
public void setName(String name)
{
    if (name == null || name.length() < 2) 
    {
        throw IllegalArgumentException("Komischer name....");
    }
    this.name = name;
}
```



}


----------



## sign (12. Aug 2010)

Marco13 hat gesagt.:


> Pauschale Aussagen sind IMMER falsch  Es gibt oft genug den Fall, dass man eine Eigenschaft
> - nur für abgeleitete Klassen oder Klassen des gleichen Packages lesbar machen will
> - für alle lesbar, aber nur für abgeleitete Klassen oder Klassen des gleichen Packages schreibbar machen will
> - sie überhaupt NUR lesbar machen will (immutable objekte)
> usw.



Getter setter müssen nach außen sichtbar sein. Wie weit kommt natürlich auf die Situation an. 



Marco13 hat gesagt.:


> Doch, wenn er mehr macht, als nur den Namen zu setzen:
> 
> ```
> public void setName(String name);
> ...


[JAVA=42]
public void setName(String name){
  doSomething(name);
}

private void doSomething(String name){
    if (name == null || name.length() < 2) 
    {
        throw IllegalArgumentException("Komischer name....");
    }
    this.name = name;
}
[/code]


----------



## nossek (12. Aug 2010)

@sign:
Die Eingangsüberlegung war ja in etwas diese:
Angenommen...
- vor der Initialisierung/Änderung vom Attribut x soll eine Parameterprüfung vorgenommen werden.
- es soll einen Konstruktor geben, der x per Argument initialisiert.

Wohin dann mit der Parameterprüfung? Es liegt wohl nahe die in den Setter von x zu tun.

Wenn wir uns so entschieden haben ergeben sich folgende Möglichkeiten:
1. Wir rufen im Konstruktor den Setter von x auf.
2. Die Parameterprüfung wird im Setter UND im Konstruktor implementiert (ganz schlecht weil doppelter code, der dann bei Änderungen an zwei Stellen geändert werden muß)
3. Wir schreiben eine weitere Methode Parameterprüfung, die vom Setter und vom Konstruktor aufgerufen wird (fördert wohl nicht grad die Lesbarkeit)

Wen man sich die drei Alternativen anschaut, dann scheint Variante 1. doch die beste zu sein. Der "natürliche Ort" für die Parameterprüfung ist der Setter. Und der wird dann sinnvollerweise auch im Konstruktor aufgerufen, falls dieser das entsprechende Attribut per Argument initialisieren soll.

Wenn ich den Thread recht verstehe, ist es unstrittig, daß Setter-Aufrufe im Konstruktor sinnvoll sein können. Es ging hier schon um komplexere Fragen im Zusamenhang mit "überschreiben von Settern im abgeleiteten Klassen" und anderen Späßen.

Anmerkungen:
1. Ich bin Anfänger, also was ich schreibe ist mit Vorsicht zu genießen!
2.Obiges bezieht sich wie gesagt nur auf Attribute, bei denen Parameterprüfung erforderlich ist. (Wenn Attribut x ein int ist und alle Werte annehmen darf, die int haben kann, dann kann man im Konstruktor natürlich direkt beigehen ohne Setter.)


----------



## sign (12. Aug 2010)

nossek hat gesagt.:


> @sign:
> Wenn wir uns so entschieden haben ergeben sich folgende Möglichkeiten:
> 1. Wir rufen im Konstruktor den Setter von x auf.
> 2. Die Parameterprüfung wird im Setter UND im Konstruktor implementiert (ganz schlecht weil doppelter code, der dann bei Änderungen an zwei Stellen geändert werden muß)
> ...



ich würd mich für die 3. entscheiden. Hier geht es doch um die Sichtbarkeit der Methoden.... doSomething(name) kann ja auch noch mehr beinhalten... warum sollte man das nach außen sichtbar machen?


----------



## maki (12. Aug 2010)

> 3. Wir schreiben eine weitere Methode Parameterprüfung, die vom Setter und vom Konstruktor aufgerufen wird (fördert wohl nicht grad die Lesbarkeit)


Doch, fördert sehr wohl die Lesbarkeit, weil verschiedene Aufgaben von verschiedenen Teilen des Codes erledigt werden.


----------



## Marco13 (12. Aug 2010)

Da würde ich wieder meine Argumente aus diesem Thread anbringen: Wenn man es tatsächlich in diesem Stil macht:

```
class Person {
    private String name;
    public Person(String name) {
        verify(name);
        this.name = name;
    }
    public void setName(String name) {
        verify(name);
        this.name = name;
    }
    private void verify(String name) { /* if something wrong throw Exception */ }
}
```
dann könnte immernoch jemand eine Methode einführen

```
....
    public void baptize(String name) {
        this.name = name;
    }
```
bei der die Überprüfung fehlt. Wenn man aber "name" irgendwie als "nur über die set-Methode setzbar" deklarieren könnte, würden sich diese Fragen nicht stellen.

(Ja, ich weiß: An den Fehlern, die durch die besagte Methode entstehen, ist im Zweifelsfall der Schuld, der die Methode eingeführt hat ... vielleicht liegt das nur daran, dass mir der Gedanke, dass Code nur von Leuten gewartet und erweitert wird, die Ahnung von dem haben, was sie da tun, einfach zu ... optimistisch erscheint...  )


----------



## nossek (12. Aug 2010)

maki hat gesagt.:


> Doch, fördert sehr wohl die Lesbarkeit, weil verschiedene Aufgaben von verschiedenen Teilen des Codes erledigt werden.


Ja, wenn die Parameterprüfung etwas aufwändiger ist bestimmt. Aber wenn sie so einfach ist wie im obigen Beispiel?


----------



## Marco13 (12. Aug 2010)

Wie einfach oder aufwändig sie ist, ändert IMHO nichts an der Frage, dass es durchaus sinnvoll sein kann, sie in eine eigene Methode auszulagern. Das wollte ich mit meinem Beispiel auch nicht in Abrede stellen - sondern damit nur verdeutlichen, dass es sinnvoll sein kann (und in diesem Fall auch wäre) im Konstruktor die set-Methode aufzurufen (oder philosophisch-theoretisch weitergedacht eben ALLE Zugriffe auf private Variablen auch innerhalb der Klasse mit settern/gettern zu machen)


----------



## nossek (12. Aug 2010)

*Grübel* 

Wenn man sich entschieden hat die Parameterprüfung in eine eigene Methode zu packen bleibt immer noch die Frage:

Im Konstruktor den Setter aufrufen oder die Parameterprüfung?

Mir scheint: Wenn oben genannte Probleme (Überschreiben der Setter) nicht auftreten können spricht nichts dagegen den Setter auch im Konstruktor zu verwenden. Oder?!?! 

Und sofern man sich für folgendes entschieden hat auch konsistenter, Marco13:


> philosophisch-theoretisch weitergedacht eben ALLE Zugriffe auf private Variablen auch innerhalb der Klasse mit settern/gettern zu machen)



Wobei: Wieso nur mit Gettern? Aua, das scheint ein neues Thema zu sein


----------



## bygones (12. Aug 2010)

Marco13 hat gesagt.:


> dann könnte immernoch jemand eine Methode einführen
> 
> ```
> ....
> ...


und da wir ja auch Tests für unsere Methoden schreiben erübrigt sich dies 


> ```
> verify(name);
> this.name = name;
> ```


wie man sieht ist das so und so eine Codekopie die anders aufgelöst werden muss.



> Getter setter müssen nach außen sichtbar sein


normalfall sollte es gar keine getter/setter geben... siehe den Prinzipien der Immunibilitaet und "Tell, dont ask"


----------



## sign (12. Aug 2010)

spinnen wir das doch weiter. Gibt bestimmt auch einen Vornamen. Die Überprüfung dann noch mal in setVorname packen? Oder doch lieber doSomthing(vorname)? 
Wenn ich zu dem Schluß komme lieber private doSomthing() zu verwenden. Dann ruf ich doch nicht im Konstruktor setName/setVorname auf die dann doSomthing() aufrufen.
Dann ruf ich doch gleich im Konstruktor doSomthing auf. 



> normalfall sollte es gar keine getter/setter geben... siehe den Prinzipien der Immunibilitaet und "Tell, dont ask"



JavaBeans-Spezifikation....


----------



## bygones (12. Aug 2010)

sign hat gesagt.:


> JavaBeans-Spezifikation....


auja - führe am besten noch Stack als sinnvolle Stack implementierung vor, oder zeig dass Vererbung richtig eingesetzt wird indem du die Properties klasse aufführst.

Man sollte von dem Gedanken wegkommen, dass alles was von Java spezifiziert wurde das genau richtige und sinnvollste ist. Das als Non-plus-Ultra zu sehen ist falsch.

Kannst gern Vorträge von Joshua Bloch anschauen indenen er eben die Prinzipien wie immunibilität und tell dont ask hervorhebt und wie er dort selbst bedauert, dass sie das damals bei Java nicht gemacht haben....


----------



## sign (12. Aug 2010)

bygones hat gesagt.:


> Man sollte von dem Gedanken wegkommen, dass alles was von Java spezifiziert wurde das genau richtige und sinnvollste ist. Das als Non-plus-Ultra zu sehen ist falsch.



Ja da hast du wohl recht. Denoch gibt es die JavaBeans-Spezifikation und auch mit gutem Grund. Bin der Meinung das man sich vorallem als Anfäger daran halten sollte. 
Kannst dich ja an Java wenden und die JavaBeans-Spezifikation anpassen lassen.


----------



## Jango (12. Aug 2010)

bygones hat gesagt.:


> Man sollte von dem Gedanken wegkommen, dass alles was von Java spezifiziert wurde das genau richtige und sinnvollste ist. Das als Non-plus-Ultra zu sehen ist falsch.



Das unterschreibe ich gern...


----------



## bygones (12. Aug 2010)

sign hat gesagt.:


> Ja da hast du wohl recht. Denoch gibt es die JavaBeans-Spezifikation und auch mit gutem Grund. Bin der Meinung das man sich vorallem als Anfäger daran halten sollte.


und das ist imo genau der falsche Ansatz.... "Wir wissen dass es nicht richtig ist... aber egal - wir bringen es den leuten bei"



sign hat gesagt.:


> Kannst dich ja an Java wenden und die JavaBeans-Spezifikation anpassen lassen.


Auch mit Bloch gesprochen "You can add something easily, but never remove it" - eine Spezifikation kannst du nicht mehr ändern. Daher muss dann der Weg gegangen werden den Leuten aufzuzeigen dass es eben nicht immer richtig ist und bessere Möglichkeiten gibt.


----------



## sign (12. Aug 2010)

Kannst dich ja an Java wenden und die JavaBeans-Spezifikation anpassen lassen. 

war doch nur ein Spaß. JavaBeans-Spezifikation: ich breite mich gemächlich auf die sjcp vor und da ists wohl besser mit den Spezifikationen Freudschaft zu schließen.


Spaßkonto: Jango vs. sign 1:1 :autsch:  (siehe unten)
oh Verwechslung.. sry


----------



## Jango (12. Aug 2010)

sign hat gesagt.:


> ...ich *breite* mich gemächlich auf die sjcp vor...



In welchen Dimensionen? :lol:

sorry


----------



## Kammerjäger (12. Aug 2010)

Jango hat gesagt.:


> Ich präzisieren es:


Wer am dem Klo sitzt sollte nicht mit dem Klopapier werfen...


----------



## Jango (12. Aug 2010)

Kammerjäger hat gesagt.:


> Wer *am dem Klo* sitzt sollte nicht mit dem Klopapier werfen...



Richtig! :lol:


----------



## Kammerjäger (12. Aug 2010)

:lol: :lol: :lol:


----------



## xhi2018 (12. Aug 2010)

bygones hat gesagt.:


> und da wir ja auch Tests für unsere Methoden schreiben erübrigt sich dies





bygones hat gesagt.:


> > ```
> > verify(name);
> > this.name = name;
> > ```
> ...


zum Beispiel die Zuweisung in der 
	
	
	
	





```
verify
```
 Methode machen...?
	
	
	
	





```
class Person {
    private String name;
    public Person(String name) {
        verify(name);
    }
    public void setName(String name) {
        verify(name);
    }
    private void verify(String name) {
        /* if something wrong throw Exception */ 
       this.name = name;
    }
}
```



bygones hat gesagt.:


> normalfall sollte es gar keine getter/setter geben... siehe den Prinzipien der Immunibilitaet und "Tell, dont ask"


danke für den Hinweis...! :rtfm:


----------



## bygones (13. Aug 2010)

xhi2018 hat gesagt.:


> Die Zuweisung in der verify Methode machen...?


ich wuerde die methode dann nicht [c]verify[/c] nennen, da es nicht wiedergibt, dass auch der Wert gesetzt wird. Aber vom prinzip her richtig ja


----------



## mvitz (13. Aug 2010)

Es ginge auch noch so, wie in commons-lang 3.0 (zumindest für != null vergleiche)


```
class Person {
    private String name;
    public Person(String name) {
        this.name = Validate.notNull(name);
    }
    public void setName(String name) {
        this.name = Validate.notNull(name);
    }
}
```


----------



## bygones (13. Aug 2010)

mvitz hat gesagt.:


> Es ginge auch noch so, wie in commons-lang 3.0 (zumindest für != null vergleiche)


ja... google-collections bzw jetzt guava bieten das auch


----------



## nossek (8. Aug 2010)

Hallo,

in den Lehrbuchbeispielen sehen Konstruktoren meist so aus:

```
public Person (String name){
    this.name = name;
}
```
Sollte man es (vorausgesetzt das jeweilige Attribut ist nicht final) nicht grundsätzlich besser so machen:

```
public Person (String name){
    setName(name);
}
```
Der zweite Fall hat den Vorteil, daß das Attribut wirklich nur an einer Stelle (also im Setter) verändert werden kann. Wenn man später auf die Idee kommt, irgendwelche Überprüfungen hinzuzufügen (wat weiß ich, ob der Name Ziffern enthält und das aber nicht erlaubt ist...), das lässt sich das ganz flott leicht implementieren...

Was meint ihr?


----------



## mvitz (13. Aug 2010)

bygones hat gesagt.:


> ja... google-collections bzw jetzt guava bieten das auch



Ja, siehe auch: Google Guava vs Apache Commons for Argument Validation | Piotr Jagielski's Blog


----------



## Nicer (13. Aug 2010)

Natürlich gibt es Setter und Getter in Java >.< überleg mal wenndu eine eigene Klasse mit Attributen erstellst! Da machstu !IMMER! Eine Getter und eine Settemethode meistens mit folgenden Namen : getAttribut und setAttribut

also das hab ich jedenfalls so gelernt


----------



## Tobias (13. Aug 2010)

Ich zitiere Marco von weiter oben in diesem Thread:



> Pauschale Aussagen sind IMMER falsch  Es gibt oft genug den Fall, dass man eine Eigenschaft
> - nur für abgeleitete Klassen oder Klassen des gleichen Packages lesbar machen will
> - für alle lesbar, aber nur für abgeleitete Klassen oder Klassen des gleichen Packages schreibbar machen will
> - sie überhaupt NUR lesbar machen will (immutable objekte)
> usw.


----------



## Nicer (14. Aug 2010)

Stimmt auch wieder , aber ich weiss nicht wie ich ihm auf diese Pauschale Frage eine Nicht Pauschale antwort hätte geben sollen


----------



## bygones (14. Aug 2010)

Nicer hat gesagt.:


> Natürlich gibt es Setter und Getter in Java >.< überleg mal wenndu eine eigene Klasse mit Attributen erstellst! Da machstu !IMMER! Eine Getter und eine Settemethode meistens mit folgenden Namen : getAttribut und setAttribut
> 
> also das hab ich jedenfalls so gelernt


dann mal schoen verlernen.....


----------

