immer Setter-Methoden verwenden?

nossek

Aktives Mitglied
Hallo,

in den Lehrbuchbeispielen sehen Konstruktoren meist so aus:
Java:
 public Person (String name){
    this.name = name;
}
Sollte man es (vorausgesetzt das jeweilige Attribut ist nicht final) nicht grundsätzlich besser so machen:
Java:
 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?
 
Zuletzt bearbeitet:

Tobias

Top Contributor
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

Aktives Mitglied
: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

Top Contributor
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

Aktives Mitglied
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

Top Contributor
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. :D

Ark
 

Ark

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

Java:
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:
Java:
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:
Java:
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

Top Contributor
@Ark: Du hast jetzt beschrieben, wie die Regeln sind, an die du dich üblicherweise hältst. Aber ich (bin antiautoritär erzogen :D 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

Aktives Mitglied
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! :oops:

@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...
 
Zuletzt bearbeitet:

Ark

Top Contributor
Aber ich (bin antiautoritär erzogen :D 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. :D 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
 
Zuletzt bearbeitet:

mvitz

Top Contributor
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

Top Contributor
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. :oops: 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

Gesperrter Benutzer
@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

Aktives Mitglied
[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

Bekanntes Mitglied
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:
Java:
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:

Java:
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
Code:
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.
 
B

bygones

Gast
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.

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
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
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...)
 

kirax

Bekanntes Mitglied
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.
 
M

maki

Gast
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

Bekanntes Mitglied
Java:
 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

Top Contributor
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.



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

Doch, wenn er mehr macht, als nur den Namen zu setzen:
Code:
public void setName(String name)
{
    if (name == null || name.length() < 2) 
    {
        throw IllegalArgumentException("Komischer name....");
    }
    this.name = name;
}



}
 

sign

Bekanntes Mitglied
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.

Doch, wenn er mehr macht, als nur den Namen zu setzen:
Code:
public void setName(String name);
{
    if (name == null || name.length() < 2) 
    {
        throw IllegalArgumentException("Komischer name....");
    }
    this.name = 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

Aktives Mitglied
@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

Bekanntes Mitglied
@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ß)
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.

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?
 
M

maki

Gast
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

Top Contributor
Da würde ich wieder meine Argumente aus diesem Thread anbringen: Wenn man es tatsächlich in diesem Stil macht:
Java:
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
Java:
....
    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... :( )
 

Marco13

Top Contributor
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

Aktives Mitglied
*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 :D
 
B

bygones

Gast
dann könnte immernoch jemand eine Methode einführen
Java:
....
    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.
und da wir ja auch Tests für unsere Methoden schreiben erübrigt sich dies :D
Java:
        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

Bekanntes Mitglied
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....
 
Zuletzt bearbeitet:
B

bygones

Gast
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

Bekanntes Mitglied
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. :p
 
B

bygones

Gast
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"

Kannst dich ja an Java wenden und die JavaBeans-Spezifikation anpassen lassen. :p
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

Bekanntes Mitglied
Kannst dich ja an Java wenden und die JavaBeans-Spezifikation anpassen lassen. :p

war doch nur ein Spaß.:oops: 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
 
Zuletzt bearbeitet:
X

xhi2018

Gast
und da wir ja auch Tests für unsere Methoden schreiben erübrigt sich dies :D
:oops:
Java:
verify(name);
this.name = name;
wie man sieht ist das so und so eine Codekopie die anders aufgelöst werden muss.
zum Beispiel die Zuweisung in der
Code:
verify
Methode machen...?
Java:
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;
    }
}
normalfall sollte es gar keine getter/setter geben... siehe den Prinzipien der Immunibilitaet und "Tell, dont ask"
danke für den Hinweis...! :rtfm:
 
Zuletzt bearbeitet von einem Moderator:

mvitz

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

Java:
class Person {
    private String name;
    public Person(String name) {
        this.name = Validate.notNull(name);
    }
    public void setName(String name) {
        this.name = Validate.notNull(name);
    }
}
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
krgewb Immer dieselbe Zufallszahl Java Basics - Anfänger-Themen 4
R Umgebungsvariable java -cp gibt immer Java-Hilfe... Java Basics - Anfänger-Themen 3
F Warum muss ich ein SSL cert immer manuell hinzufügen? Java Basics - Anfänger-Themen 46
M Queue-Datenstruktur: nach dem Elementen entfernen, das Ergebnis ist immer noch nicht optimal. Java Basics - Anfänger-Themen 3
K Warum werden immer noch doppelte Zahlen ausgegeben ? Java Basics - Anfänger-Themen 13
J Componente immer in Front halten, wie? Java Basics - Anfänger-Themen 5
berserkerdq2 Brauche ich while != -1, wenn ich immer einen BufferedReader verwende? Java Basics - Anfänger-Themen 8
berserkerdq2 Habe ein Spiel entwickelt, dass immer in der 4 Runde einen cast-Fehler erhält Java Basics - Anfänger-Themen 3
berserkerdq2 Spiel hängt sich immer in der 4 Runde auf, obwohl ich jede Runde das gleiche mache Java Basics - Anfänger-Themen 1
berserkerdq2 An selbst ersteller txt Datei immer Text dranhängen, ohne den vorherign Text zu löschen Java Basics - Anfänger-Themen 8
K In andere Zahlensysteme umwandeln, wann klappt immer der Trick mit log? Java Basics - Anfänger-Themen 6
F Wieso wird immer die falsche Mausposition angegeben? Java Basics - Anfänger-Themen 1
D Codeblöcke, die immer wieder im Programmverlauf benötigt werden Java Basics - Anfänger-Themen 5
chocobear26 Interface JOptionPane - Dialog_Fenster zeigt immer vorherige Eingabe an. Java Basics - Anfänger-Themen 4
C Objekt1.equals(Objekt2) = immer false. Wieso? Java Basics - Anfänger-Themen 22
I Array übernimmt immer den letzten Input. Java Basics - Anfänger-Themen 14
tom.j85 Doppelte Foreach Schleife: Am Ende wird immer das Gleiche Objekt eingefügt Java Basics - Anfänger-Themen 4
M Untersuchen ob ein Graph nach entfernen einer Kante immer noch zusammenhängend ist Java Basics - Anfänger-Themen 70
J Zweck von Interfaces immer noch nicht klar Java Basics - Anfänger-Themen 3
M Array immer wieder um ein Element erweitern Java Basics - Anfänger-Themen 6
CptK Methoden Event bei gedrückter Maustaste immer wieder ausführen Java Basics - Anfänger-Themen 1
CptK Klassen Event bei gedrückter Maus immer wieder mit Pause ausführen Java Basics - Anfänger-Themen 2
IMain23 2d Array variabler Spaltenwert, Spaltenwert immer um eins erhöhen Java Basics - Anfänger-Themen 3
M JTextField blitzt immer wieder nur auf Java Basics - Anfänger-Themen 12
N Arbeitsspeicher nach kompilieren immer voller Java Basics - Anfänger-Themen 6
S Immer das selbe mit den Schleifen Java Basics - Anfänger-Themen 24
H OOP eine Zahl immer weiter durch 2 teilen Java Basics - Anfänger-Themen 15
B Operatoren Java berechnet immer 0? Java Basics - Anfänger-Themen 3
J Timer bauen, Main Methode immer wieder neu starten Java Basics - Anfänger-Themen 13
N Funktion funktioniert nicht immer Java Basics - Anfänger-Themen 6
I Methoden Schleife immer wieder durchlaufen lassen Java Basics - Anfänger-Themen 15
3 JFrame immer im Hintergrund Java Basics - Anfänger-Themen 1
F Immer wieder gleiche Zufallszahl? Java Basics - Anfänger-Themen 4
J Operatoren Random wird nur einmal erstellt und dann immer verwendet Java Basics - Anfänger-Themen 2
S Repaint() in der Schleife funktioniert nicht immer Java Basics - Anfänger-Themen 5
S Variable in JTextField soll immer um 5 zunehmen Java Basics - Anfänger-Themen 8
schoenosrockos JButton füllt immer das ganze frame Java Basics - Anfänger-Themen 1
N JList + DefaultListModel + JScrollPane --> ensureIndexIsVisible funktioniert nicht immer Java Basics - Anfänger-Themen 1
N Immer Aktiv sein. Java Basics - Anfänger-Themen 8
D Array wird immer mir 100 für jeden Wert initialisiert? Java Basics - Anfänger-Themen 2
J Ergebnis immer 0 Java Basics - Anfänger-Themen 8
S If-Anweisunng ist IMMER true Java Basics - Anfänger-Themen 2
F Inhalt einer Variable auswerten, die sich immer wieder ändert Java Basics - Anfänger-Themen 1
S UserPref und Java Application klappt immer nicht. Java Basics - Anfänger-Themen 2
Ponychan95 Erste Schritte Switch fällt immer bis zum default durch Java Basics - Anfänger-Themen 4
F String immer weiter nach Bedarf vergrößern Java Basics - Anfänger-Themen 3
X Muss man das immer so schreiben o.O Java Basics - Anfänger-Themen 3
F Timer beendet nicht immer Java Basics - Anfänger-Themen 2
N Boolean Werte - immer "false" Java Basics - Anfänger-Themen 5
P JavaFX Textfelder geben immer null zurück Java Basics - Anfänger-Themen 8
M zufälliges Setzen von Schiffen in while klappt nicht immer Java Basics - Anfänger-Themen 3
S Random IDs immer 10-stellig? Wie? Java Basics - Anfänger-Themen 5
B Klassen Objekte werden immer überschrieben Java Basics - Anfänger-Themen 10
T Muss ein Parametertest immer eine eigene Testklasse sein? Java Basics - Anfänger-Themen 3
C JavaMail funktioniert nicht immer Java Basics - Anfänger-Themen 8
J .txt Datei "einlesen "und in String speichern ergibt immer NULL Java Basics - Anfänger-Themen 17
M Noch immer Probleme mit exec Java Basics - Anfänger-Themen 15
A Java Arrays immer um eins "vergrößern" Java Basics - Anfänger-Themen 4
E Input/Output Drucken am Mac immer gleiche Schriftgröße?!? Java Basics - Anfänger-Themen 2
R Hashset.add(Array) liefert immer true? Java Basics - Anfänger-Themen 23
I immer die gleiche Zufallszahl Java Basics - Anfänger-Themen 9
F Funktion immer zur vollen Stunde? Java Basics - Anfänger-Themen 3
A Warum immer das "J" im Klassennamen? Java Basics - Anfänger-Themen 10
M Erste Schritte Eclipse führt immer das gleiche Programm aus Java Basics - Anfänger-Themen 6
B Schlüsselworte this - immer oder nur wenn wirklich notwendig? Java Basics - Anfänger-Themen 9
A Wieso wird immer 0 ausgegeben? Java Basics - Anfänger-Themen 4
C 2 Objekte, 1 immer Null? Java Basics - Anfänger-Themen 8
P Classpath falscher Classpath, aber nicht immer Java Basics - Anfänger-Themen 19
E JButtons auf JFrame nicht immer sichtbar Java Basics - Anfänger-Themen 4
Helgon Observer Pattern - hasChanged() immer false Java Basics - Anfänger-Themen 10
P toString-Methode gibt immer null vor Variable aus Java Basics - Anfänger-Themen 9
L Immer diese Arrays Java Basics - Anfänger-Themen 11
M OOP Graphics immer selbstbezihend Java Basics - Anfänger-Themen 12
D . ist nicht immer .!? Java Basics - Anfänger-Themen 18
S Dezimale Konstanten sind immer positiv oder null - was heisst das den genau? Java Basics - Anfänger-Themen 2
L JTextField getText() gibt immer null zurück Java Basics - Anfänger-Themen 10
J \n funktioniert nicht immer Java Basics - Anfänger-Themen 10
L Woerterbuch liefert immer "null" Java Basics - Anfänger-Themen 41
J Datentypen Math.sqrt() immer NaN Java Basics - Anfänger-Themen 8
T Datei so speichern das sie immer erreichbar ist Java Basics - Anfänger-Themen 2
Os-Programming Checkbox immer wieder überprüfen Java Basics - Anfänger-Themen 13
ruutaiokwu final wenn immer möglich verwenden? Java Basics - Anfänger-Themen 30
E Input/Output Datei immer weiter erweitern Java Basics - Anfänger-Themen 4
D Muss ich eigentlich immer auf die Verwendung des richtigen Datentyps achten? Java Basics - Anfänger-Themen 7
B if erzeugt nur immer ein FALSE Java Basics - Anfänger-Themen 2
M Tabelle mit immer sortiertem Inhalt Java Basics - Anfänger-Themen 5
F Midi-Sequenzer gibt immer denselben, schrägen Ton aus? Java Basics - Anfänger-Themen 2
M isHidden() von java.io.File liefert immer true in Windows Java Basics - Anfänger-Themen 3
A Immer wird "gut" ausgegeben Java Basics - Anfänger-Themen 14
G Immer mehr Threads beim Selbstaufruf der main-Methode Java Basics - Anfänger-Themen 3
M immer noch usedelimiter Java Basics - Anfänger-Themen 4
R ARRAY/List die sich immer wieder von vorne neu auffüllt ? Java Basics - Anfänger-Themen 21
Y JFrame immer im Focus ? Java Basics - Anfänger-Themen 7
N ArrayList wird immer um zwei Elemente erweitert Java Basics - Anfänger-Themen 9
J cast zu int immer 0.. Java Basics - Anfänger-Themen 6
B Process.getInputStream immer leer Java Basics - Anfänger-Themen 3
T ArrayList immer die letzte Zeile Java Basics - Anfänger-Themen 2
C Array ist befüllt, doch gibt sie immer 0 zurück Java Basics - Anfänger-Themen 3
F Immer nur drei Werte lesen Java Basics - Anfänger-Themen 9
B Warum kommt immer die 0 als Ergebnis? Was habe ich falsch gemacht? Java Basics - Anfänger-Themen 18

Ähnliche Java Themen

Neue Themen


Oben