# Parameter einschränken



## Sophie (3. Okt 2011)

Hallo

Ich habe hier folgende Klasse


```
public class Auto extends Fahrzeug {

	/**
	 * @param passagiere
	 * @param platz
	 */
	protected Car(int passagiere) {
		super(passagiere, platz,preis, passagierePreis);
		
		platz = 5;
		preis = 200;
		passagierePreis = 30;
	}

	
}
```

Ich möchte jetzt, dass man kann nur maximal 4 Passagiere angegeben kann.

Wie kann ich das denn machen?


----------



## hdi (3. Okt 2011)

Hm in Verbindung mit dem super-Aufruf gar nicht mal so einfach.. Grundsätzlich kannst du ja sowas wie

```
if(passagiere > 4){ 
    // ...
}
```

machen. Aber der super-Aufruf muss die erste Anweisung im Konstruktor sein. Da muss jetzt das Design stimmen: In der Vaterklasse Fahrzeug muss der Wert für Passagiere auf jeden Fall über einen Setter festgesetzt werden:


```
public Fahrzeug(int passagiere, ...){
   setPassagiere(passagiere);
}

public void setPassagiere(int passagiere){
   this.passagiere = passagiere;
}
```

Wenn das so in der Klasse Fahrzeug aussieht, kannst du nun in der Kindklasse Car diesen Setter überschreiben. Dank Polymorphie (dynamic binding) landest du über den Konstruktor der Klasse Fahrzeug im Setter der Klasse Car. Und dort sieht der wie folgt aus:


```
@Override
public void setPassagiere(int passagiere){ 
   if(passagiere <= 4){
         super.setPassagiere(passagiere); // Setter aus Fahrzeug-Klasse
   }
   else{
         // Hier reagierst du nun: Exception werfen, Meldung anzeigen, was auch immer
   }
}
```

PS: Schau erstmal dass dein Code kompiliert.. Deine Klasse heißt Auto, der Konstruktor heißt Car -> Compile Error!. Du übergibst dem super-Aufruf Variablen, die nirgendwo in der Klasse stehen -> Compile Error! Und da stehen noch einige andere Variablen die nirgends deklariert wurden. Aber vllt hast du das jetzt der Übersicht halber rausgenommen.


----------



## guest0815 (3. Okt 2011)

In solchen Fällen wäre sicherlich eine Factory oder ein Builder sinnvoll. Diese(r) könnte alle an der Objekterzeugung hängenden Constraints überprüfen und bei Bedarf eine Exception werfen bzw. null zurückgeben.


----------



## Spacerat (3. Okt 2011)

guest0815 hat gesagt.:


> In solchen Fällen wäre sicherlich eine Factory oder ein Builder sinnvoll. Diese(r) könnte alle an der Objekterzeugung hängenden Constraints überprüfen und bei Bedarf eine Exception werfen bzw. null zurückgeben.


[IRONIE]Na Sicher... BufferedImage wird ja auch über 'ne Factory instanziert[/IRONIE]Werte auf Gültigkeit überprüfen und 'ne entsprechende Exception (IllegalArgumentException) werfen oder auf Maximalwerte reduzieren. Möglicherweise vorher auch noch diese Maximalwerte als öffentliche Konstante ("public static final int") festlegen. Wenn diese Werte dann von Klasse zu Klasse (in diesem Fall Fahrzeuge) abweichen, muß man sie halt in jeder Klasse einzeln festlegen, es sei denn, man lässt sich auf nicht ganz triviales und unsauberes Reflection ein. Zumindest ist mir keine andere Methode bekannt, wie man in einer Vaterklasse Konstanten ändern kann.


----------



## tagedieb (3. Okt 2011)

Deinen Constructor von Auto/Car hab ich auch nicht verstanden. Du musst alle (fixen) Parameter an die super Klasse uebergeben (nicht nur die passagiere). Das Zuweisen der Variablen sollte generel in der Klasse gemacht werden in der die Variablen deklariert wurden.

Du kannst dann auch einen weiteren Parameter fuer die Max Passagieranzahl uebergeben oder wie im Beispiel unten eine abstracte Methode definieren. Das Validieren und Zuweisen der Variablen wird im Constructor von Fahrzeug durchgefuehrt. 



```
abstract public Fahrzeug {
    int passagiere, platz, preis, passagierePreis;
    protected Fahrzeug(passagiere, platz,preis, passagierePreis) {
        if (passagiere > getMaxPassagiere()) {
            throw IllegalArgumentException();
        }
        this.passagiere = passagiere;
        this.platz = platz;
        ...
    }

    abstract protected int getMaxPassagiere();
 }


public class Auto extends Fahrzeug {
 
    /**
     * @param passagiere
     * @param platz
     */
    protected Auto(int passagiere) {
        super(passagiere, 5, 200, 30);
    }

    protected int getMaxPassagiere() {
        retrun 4;
    }
    
}
```


----------



## Andi_CH (3. Okt 2011)

Es gibt keine (mir bekannten ) Einplätzigen Autos - 3 Plätzer - hm na ja - gab es früher mal ... wenn schon sollte man das komplett überprüfen <=2 ...

Etwas umständlich aber sehr typsicher ginge das auch mit einem enum, aber kann mir wer erklären warum


```
enum Platzzahl {
  2, 4, 5
}
```

nicht geht und das die studiert haben, als sie ordinal() als final deklariert haben?


```
package com.javaforum;

public class Test {

	public enum Platzzahl {
		zwei, vier, fuenf;

		public int value(){
			switch (this) {
			case zwei: return 2;
			case vier: return 4;
			case fuenf: return 5;
			}
			return 0;
		};
	}

	public static class Auto {
		private final int sitzzahl;

		public Auto(Platzzahl anzahl) {
			sitzzahl = anzahl.value();
		}
	}

	public static void main(String[] args) {
		Auto meinWagen = new Auto(Platzzahl.vier);
	}
}
```


----------



## guest0815 (3. Okt 2011)

Spacerat hat gesagt.:


> [IRONIE]Na Sicher... BufferedImage wird ja auch über 'ne Factory instanziert[/IRONIE]


Ja und, ist die Java-API irgendetwas in Stein gemeißeltes? Sind die dortigen Vorgehensweisen per Definition korrekt? Und woher nimmst du die Annahme, dass sie Allgemeingültigkeit besitzen?
Es gibt nunmal verschiedene Vorgehensweisen der Objekterzeugung. Über die Vor- und Nachteile Klassen die Verantwortlichkeit ihrer eigenen Instanzen-Erzeugung aufzuerlegen wurde in der Fachliteratur nun wirklich schon lang und breit diskutiert...
Wenn du diese Diskussion versäumt hast, dann hole das nach. Auf dieses kindische [IRONIE]-Niveau werde ich mich jedenfalls nicht herablassen.


----------



## tfa (3. Okt 2011)

Factorys bzw. Fabrikmethoden sind erstmal keine schlechte Idee. Damit ist man flexibler als mit direkten Konstruktoraufrufen. Keine Ahnung, warum BufferedImage ein Gegenargument darstellen sollte und was das mit Ironie zu tun hat. Auch der Zusammenhang zu öffentlichen Konstanten und Reflection erschließt sich mir nicht so ganz...


----------



## Spacerat (3. Okt 2011)

@guest0815 & tfa: Hey ihr zwei, es geht hier bei der Instanzierung der Klasse blos um die ordinäre Übergabe eines primitiven Datentypen und dessen Begrenzung auf gültige Werte. Macht ihr es mit 'ner Factory-Methode und gut. Für mich ist diese Art jedenfalls vollkommen überzogen. Wem sich der Zusammenhang mit BufferedImage nicht erschliesst, hat es mit Sicherheit schon geschafft, ein solches mit negativen Werten zu instanzieren - möglicherweise über eine Factory-Methode in welcher er das per Reflection bewerkstelligt. Tja, da ist es ja schon wieder, dieses Reflection. Die Klasse "Auto" ist ein Fahrzeug mit sagen wir maximal 4 Plätzen, eine Klasse "LKW" hat meinetwegen maximal 3. Diese Werte kann man für alle zugänglich als Klassenkonstanten definieren. Leider ginge das nur in jeder Klasse einzeln. Besser wäre es, wenn man diese Konstante in der Vaterklasse hat, dort bekommt man sie aber ohne Reflection nicht hin bzw. nicht geändert.
Im übrigen; Diese abstrakte "getMaxPassagiere()"-Methode ist natürlich der Hit... genau so geht's


----------



## hdi (3. Okt 2011)

> Diese abstrakte "getMaxPassagiere()"-Methode ist natürlich der Hit... genau so geht's



Oh ja, richtig. Ist natürlich noch besser als mein Vorschlag mit dem Override des Setters. I blame the time  @TO mach's so!


----------



## tfa (3. Okt 2011)

Spacerat hat gesagt.:


> @guest0815 & tfa: Hey ihr zwei, es geht hier bei der Instanzierung der Klasse blos um die ordinäre Übergabe eines primitiven Datentypen und dessen Begrenzung auf gültige Werte. Macht ihr es mit 'ner Factory-Methode und gut. Für mich ist diese Art jedenfalls vollkommen überzogen. Wem sich der Zusammenhang mit BufferedImage nicht erschliesst, hat es mit Sicherheit schon geschafft, ein solches mit negativen Werten zu instanzieren - möglicherweise über eine Factory-Methode in welcher er das per Reflection bewerkstelligt. Tja, da ist es ja schon wieder, dieses Reflection.


Irgendwie scheinen wir verschiedene Ansichten davon zu haben, was Factory-Methoden sind und wie sie funktionieren. Warum um Himmels Willen immer diese Reflection? Was hat das miteinander zu tun? Ich behaupte ja gar nicht, dass man jeden Konstruktor-Aufruf durch einen Factory-Aufruf ersetzen sollte. Aber hin  und wieder ist es sinnvoll.



> Die Klasse "Auto" ist ein Fahrzeug mit sagen wir maximal 4 Plätzen, eine Klasse "LKW" hat meinetwegen maximal 3. Diese Werte kann man für alle zugänglich als Klassenkonstanten definieren. Leider ginge das nur in jeder Klasse einzeln. Besser wäre es, wenn man diese Konstante in der Vaterklasse hat, dort bekommt man sie aber ohne Reflection nicht hin bzw. nicht geändert.


Schon wieder Reflection! Wieso sollte man solche Konstanten in der Oberklasse definieren, und wie bekommt man sie mittels Reflection "dort hin"? Konstanten werden einfach dort definiert, wo sie hingehören (sie müssen nichtmal öffentlich sein)- meinetwegen auch zentral in einer Factory-Klasse.


> Im übrigen; Diese abstrakte "getMaxPassagiere()"-Methode ist natürlich der Hit... genau so geht's


Kann man natürlich machen. Ob das im Einzelfall sinnvoll ist, muss man sich eben überlegen. Wenn man eine handvoll Attribute hat und für jedes eine getMaxValue- und getMinValue-Methode definieren und implementieren will, wird das natürlich schnell unübersichtlich. Zumal jede dieser Methoden ja nichts weiter macht, als einen Konstanten Wert zurück zu liefern. Wegen ein paar Prüfungen sich seine Schnittstellen so aufzublähen fände ich jedenfalls vollkommen überzogen.


----------



## Spacerat (3. Okt 2011)

Die Konstanten dienen natürlich dazu, den Anwender über die maximale Anzahl der Passagiere zu informieren. Wenn der Anwender sie nicht nutzt und deswegen ungültige Werte übergibt, ist das sein Problem.
Mit Reflection:
	
	
	
	





```
import java.lang.reflect.Field;

public abstract class Vehicle1
{
	public static final	int MAX_PASSENGERS = -1; // invalid value
	protected int passengers; 

	protected Vehicle1(int passengers)
	{
		if(passengers > MAX_PASSENGERS || passengers < 0) {
			throw new IllegalArgumentException("illegal value for passengers: " + passengers);
		}
		this.passengers = passengers;
	}
}

final class Car1
extends Vehicle1
{
	static {
		try {
			Field f = Vehicle1.class.getDeclaredField("MAX_PASSENGERS");
			f.setAccessible(true);
			f.set(null, 4);
			f.setAccessible(false);
		} catch(Exception ex) {
			throw new ExceptionInInitializerError(ex);
		}
	}

	Car1(int passengers)
	{
		super(passengers);
	}
}

final class Transporter1
extends Vehicle1
{
	static {
		try {
			Field f = Vehicle1.class.getDeclaredField("MAX_PASSENGERS");
			f.setAccessible(true);
			f.set(null, 3);
			f.setAccessible(false);
		} catch(Exception ex) {
			throw new ExceptionInInitializerError(ex);
		}
	}

	Transporter1(int passengers)
	{
		super(passengers);
	}
}
```
Ohne Reflection:
	
	
	
	





```
public abstract class Vehicle2
{
	protected int passengers; 

	protected Vehicle2(int passengers)
	{
		this.passengers = passengers;
	}
}

final class Car2
extends Vehicle2
{
	public static final	int MAX_PASSENGERS = 4;

	Car2(int passengers)
	{
		super(passengers);
		if(passengers > MAX_PASSENGERS || passengers < 0) {
			throw new IllegalArgumentException("illegal value for passengers: " + passengers);
		}
	}
}

final class Transporter2
extends Vehicle2
{
	public static final	int MAX_PASSENGERS = 3;

	Transporter2(int passengers)
	{
		super(passengers);
		if(passengers > MAX_PASSENGERS || passengers < 0) {
			throw new IllegalArgumentException("illegal value for passengers: " + passengers);
		}
	}
}
```
Bei der ersten Version hätte ich natürlich auch arge Bauchschmerzen, diese hätte aber den Vorteil, dass die Konstante in jeder Unterklasse vorhanden ist, von diesen jedoch recht umständlich "validiert" werden muß. Die zweite Version ist dagegen schon sauberer, birgt aber den Nachteil, dass diese Konstante erstens vergessen bzw. anders benannt werden kann und zweitens die Überprüfung der Gültigkeit Sache der jeweiligen Unterklasse bleibt. Als drittes wäre die Konstante hier auch noch völlig uninteressant, weil sich wohl kein Mensch die Mühe machen wird, diese bei einer Fülle an verschiedenen Fahrzeugen auch noch abzufragen weil ohnehin die grosse Gefahr besteht z.B. einem Auto die Konstante eines Transporters zu übergeben.

Und nun der Sinn einer Factory-Methode? Vor allem, wenn die Anzahl der konkreten Klassen von Fahrzeugen noch während der Entwicklung steigt, wirds doch schon schwierig oder nicht?

Wie gesagt: Simpel und fein; Diese abstrakte "getMaxPassagiere()-Methode.


----------



## guest0815 (3. Okt 2011)

Jetzt müsstest du nur noch erklären was dieser an den Haaren herbeigezogene Frickelkram* mit einer Factory zu tun haben soll, geschweige denn wie er in irgendeiner Art und Weise als Argument gegen Factories dienen soll. Irgendwie habe ich den Verdacht, du hast mal irgendwas von Reflection gehört, wie böse das doch ist, und seitdem ist alles, was über einfachste Konzepte hinausgeht, z.B. alle Entwurfsmuster, für dich "Reflection" und damit "Teufelswerk". Alles klar ...

* Warum Frickelkram? Weil solcher Code hat absolut nichts in den Domänenklassen zu suchen hat.


----------



## Spacerat (3. Okt 2011)

guest0815 hat gesagt.:


> Jetzt müsstest du nur noch erklären was dieser an den Haaren herbeigezogene Frickelkram* mit einer Factory zu tun haben soll, geschweige denn wie er in irgendeiner Art und Weise als Argument gegen Factories dienen soll. Irgendwie habe ich den Verdacht, du hast mal irgendwas von Reflection gehört, wie böse das doch ist, und seitdem ist alles, was über einfachste Konzepte hinausgeht, z.B. alle Entwurfsmuster, für dich "Reflection" und damit "Teufelswerk". Alles klar ...
> 
> * Warum Frickelkram? Weil solcher Code hat absolut nichts in den Domänenklassen zu suchen hat.


Neee... nix ist klar... Natürlich haben meine Klassen nichts mit Factorys zu tun - nur du & tfa redeten davon, während ich das von vorne herein in diesem Fall für völlig überzogen hielt, Entwurfsmuster sind mir durchaus geläufig, ebenso Reflection, wie man sieht. Teufelswerk ist beides nur dann, wenn man es an den falschen Stellen einsetzt. Man kann Schrauben auch durchaus mit 'nem Hammer versenken. Deswegen hast du zumindest mit dem Frickelkram schon mal recht.
Aber:
1. Wo definierst du eine Factory-Methode? Richtig! In der Urvater-Klasse, hier Fahrzeug.
2. Was müsstest du einer Factory-Methode übergeben, damit du eine Instanz der gewünschten Unterklasse mit den übergebenen Attributen bekommst? Wieder korrekt, einen winzig kleinen Hinweis auf die gewünschte Klasse und sei es nur der Name. Wie du sie innerhalb der Factory-Methode instanzierst ist ganz allein dein Problem.
3. Je nach Implementation musst du deine Factory-Methode möglicherweise überarbeiten, wenn weitere konkrete Fahrzeug-Ableger hinzugefügt werden. Obwohl Factory-Methoden eigentlich in der Lage sein sollten, auf solche Änderungen automatisch zu reagieren.
4. Ich hab' immer noch nicht das kleinste Beispiel, wie ihr es mit ner Factory-Methode lösen würdet.
Alles klar?


----------



## tfa (4. Okt 2011)

@Spacerat

Zu deiner Reflection-Lösung: Achdumeinegüte.

Zu deinen anderen Problemen: Ich glaub, du denkst zu kompliziert.
Eine Factory-Methode kannst du definieren wo du willst. In der Klasse selber, in der Oberklasse oder in einer ganz neuen. Wenn du eine neue Klasse erfindest, muss man ggf. auch eine neue Factory-Methode implementieren. Das ist nicht unbedingt generisch (und keine Reflection-Frickelei). Deine so praktischen getMin/Max-Methoden musst du ja implementieren, oder?
Ansonsten habe ich weder Zeit noch Lust, dir Grundlagen beizubringen. Du kannst ja mal hier nachlesen, viele ganz einfache Factory-Methoden.


----------



## Spacerat (4. Okt 2011)

tfa hat gesagt.:


> Zu deiner Reflection-Lösung: Achdumeinegüte.


Einverstanden, meine 2. Lösung ist natürlich auch nicht die beste. 


tfa hat gesagt.:


> Zu deinen anderen Problemen: Ich glaub, du denkst zu kompliziert.


Ich doch nicht! Vertreter der Factory-Methode aber und zwar genau deswegen:





tfa hat gesagt.:


> Eine Factory-Methode kannst du definieren wo du willst. In der Klasse selber, in der Oberklasse oder in einer ganz neuen. Wenn du eine neue Klasse erfindest, muss man ggf. auch eine neue Factory-Methode implementieren. *Das ist nicht unbedingt generisch* (und keine Reflection-Frickelei).





tfa hat gesagt.:


> Deine so praktischen getMin/Max-Methoden musst du ja implementieren, oder?


War zwar nicht meine Idee aber dennoch... Richtig. Man achte auf das muß... das ist wichtig.





tfa hat gesagt.:


> Ansonsten habe ich weder Zeit noch Lust, dir Grundlagen beizubringen. Du kannst ja mal hier nachlesen, viele ganz einfache Factory-Methoden.


Ist doch auch nicht nötig... Ich weis was Factory-Methoden sind und wofür man sie einsetzt. Halte sie ja in diesem Fall nicht grundlos für überzogen. Hier steht auch nirgends, dass ich in anderen Fällen nicht zu Factory-Methoden raten würde, z.B. beim Laden von Verschlüsselungsalgorythmen sind sie durchaus angebracht.


----------



## Tomate_Salat (4. Okt 2011)

Ich habe nichts gegen FactoryMethoden in dem Fall, aber ich finde, für einen Anfänger reicht der Vorschlag von Hdi vollkommen aus. Ggf könnte man die parentklass erweitern, dass man mitgibt, wieviele Sitze maximal belegbar sind. Ähnlich:


```
public class Auto
{
	private final int sitze;
	
	public Auto(final int sitze)
	{
		this.sitze=sitze;
	}
	
	public int getSitze() {
		return sitze;
	}
}

public class MercedesCKlasse extends Auto
{
	public MercedesCKlasse()
	{
		super(5);
	}
	
	public boolean setPersonenInsAuto(final int personen)
	{
		if(personen<=getSitze()) {
			// tür auf -> personen rein -> tür zu
			return true;
		}
		
		return false;
	}
}
```


----------



## bygones (4. Okt 2011)

Spacerat hat gesagt.:


> 4. Ich hab' immer noch nicht das kleinste Beispiel, wie ihr es mit ner Factory-Methode lösen würdet.
> Alles klar?




```
public class FahrzeugFactory() {
  public static Fahrzeug createCar() {
     return new Fahrzeug(4);
  }

  public static Fahrzeug createLKW() {
     return new Fahrzeug(3);
  }

  public static Fahrzeug createSuperVan() {
     return new Fahrzeug(25);
  }
}
```
....


----------



## sillydude (5. Okt 2011)

So hallo Leute,

ich denke hdi hat den besten ansatz für anfänger geliefert, wobei ich sagen muss, es ist immer interessant zu sehen, wie fortgeschritten dies lösen würden. Doch die hälfte davon versteh ich nicht, naja hier ist meine (auf hdi´s tipp basierende, jedoch leicht geänderte) lösung:


```
package cars;

public class Fahrzeug {
    int passagiere; 
    
    public Fahrzeug(int passagiere) {
        if (passagiere <= 4 && passagiere > 0) {
            this.passagiere = passagiere;
            System.out.println("Fahrzeug mit " + passagiere + " Passagier/en wurde erzeugt");
        }
        else
            System.out.println("Die Personenanzahl muss mind. 1 und max 4 betragen");
    }
}
```


```
package cars;

public class Auto extends Fahrzeug {

    protected Auto(int passagiere) {
        super(passagiere);
    }
 
    
}
```


```
package cars;

public class cartest {
    public static void main (String [] args) {
        Auto auto1 = new Auto(0);
        Auto auto2 = new Auto(1);
        Auto auto3 = new Auto(4);
        Auto auto4 = new Auto(5);
    }
}
```

Die ungenutzten Variablen habe ich einfach mal weggelassen, da sie nirgends deklariert waren, jedoch denke ich and em solls nicht scheitern.


----------



## fastjack (5. Okt 2011)

Leute, wozu brauche ich dafür Builder-Pattern oder gar Reflections??? Builder-Pattern ist fehl am Platz, Reflections zeigen das man meistens nicht objektorientiert gedacht hat. Entweder macht man verschiedene Autos wie bygones (was auch bei Autos eigentlich logisch ist) oder, wenn es nur ein bestimmtes Auto gibt, checkt man das unter Preconditions ab, also Parameter prüfen und IllegalArgumentException werfen.


----------

