# Zusammenfassen verschiedener ähnlicher Methoden



## Bober (10. Sep 2012)

Hallo,


ich beschäftige mich zur zeit mit dem play framework in der version 1.2.5 und habe nun folgende frage:

ich habe viele Methoden in einem Controller, die alle "das gleiche" machen:


```
public static void run0(Calculation0 calculation) {

		calculation.calculate();

		renderTemplate("Calc_output/0.html",t,calculation);
	}
public static void run1(Calculation1 calculation) {

		calculation.calculate();

		renderTemplate("Calc_output/1.html",t,calculation);
	}
public static void run2(Calculation2 calculation) {

		calculation.calculate();

		renderTemplate("Calc_output/2.html",t,calculation);
	}
```

ich würde nun gerne eine allgemeine Methode schreiben, die alle anderen ersetzt.

Das Problem ist, dass die verschiedenen callculations unterschiedliche variablen haben, auf die ich jeweils in einer view zugreife. 


```
#{field calculation.a'}
        <div class="field">         
            <label for="${field.id}">Desired username : </label>
            <input id="${field.id}" type="text" name="${field.name}" value="${field.value}" class="${field.errorClass}" />
            <span class="error">${field.error}</span>
        </div>
        #{/field}
```

Wenn ich nun eine Methode mit dem Interface als Datentyp formuliere, kann ich nicht mehr auf die Variablen zugreifen:

```
public static void run(Calculation calculation,int t) {

		calculation.calculate();

		renderTemplate("Calc_output/"+t+".html",t,calculation);
	}
```

Gibt es eine Möglichkeit, der Methode beim aufruf den Datentyp des Übergabeparameters mitzuteilen?

ich habe auch schon an generische Datentypen gedacht, aber da kann man bei einer Methode ja nicht explizit den Datentyp definieren, wenn man sie aufruft. (oder liege ich da falsch?)


```
public static <T extends Calculation> void run(T calculation, int t) {

		calculation.calculate();

		renderTemplate("Calc_output/"+t+".html",t,calculation);
	}
```



Gruß,


Bober


----------



## JCODA (10. Sep 2012)

ich würde sagen du erweiterst dein Interface Calculation um die Methode void doRun(KlasseX x);, wobei KlasseX die Klasse ist, die renderTemplate implementiert. Somit kann sich jede Implementierung von deinem Interface selbst raussuchen was sie tut.


----------



## Bober (10. Sep 2012)

danke für die Antwort JCODA.

Leider hilft mir das nicht weiter, da ich wie gesagt aus der jeweiligen view Zugriff auf die Variablen der entsprechenden klasse brauche, d.h. ich bräuchte eine art allgemeine Methode, die ich mir so vorstelle:

(frei erfundener quellcode)


```
public static void run<T extends Calculation>(T calculation){
...

}
```

wobei mit dem T die exacte Unterklasse bestimmt werden könnte:


```
run<Calculation1>(calculation)
```


Oder vll hat jemand, der sich mit dem play framework auskennt einen anderen vorschlag?
(ich müsste dann wohl das problem noch genauer schildern)


----------



## SuppenGeist (10. Sep 2012)

Ich denke, du solltest dir nochmal grundlegende Gedanken zu deinem Klassendesign machen. Die Instazvariablen sollten NIEMALS public sein. Außerdem sollte nur der "Inhaber" der Instanzvariablen mit diesen arbeiten.

Aber zu dem Problem:
Du könntest eine Superklasse erstellen

```
public class Calculation {
protected String _name;

public Calculation() {}

public void setName(String newName) {
if(newName!=null)
_name=newName;
}
public String getName() {
return _name;
}
}
```

Dann erben die Calculation0,etc. von dieser Klasse, du setzt die einzelnen Namen mittels 
	
	
	
	





```
instanz.setName("test");
```
. Und dann kannst du die einzelnen Instanzen indentifizieren.




```
public void run(Calculation calc,...) {
if(calc.getName().equals("test") {
//TODO:irgentwas
}
}
```

Wenn du die einzelnen Klassentypen außeinanderhalten willst, kannst du jeder Klasse eine statische Variable hinzufügen:


```
public class Calculation0 {
public static final String CLASS_TYPE="Calculation0";

public String getClassType() {
return CLASS_TYPE;
}
}
```

Jetzt kannst du eine einfache Typenprüfung machen:

```
public void run(Calculation calc,...) {
if(calc.getClassType().equals("Calculation0")) {
//TODO:irgentwas
}
}
```

Natürlich müsste bei dieser Variante die Superklasse "Calculation" eine Methode 
	
	
	
	





```
public abstract String getClassType();
```
 implementiren.

Allerdings wie gesagt, solche Probleme deuten auf ein schlechhtes Klassendesign hin. Du solltest dich in dieser Richtung nochmal ein bisschen was durchlesen


----------



## tribalup (10. Sep 2012)

Schau dir mal das template method pattern an.


----------



## Bober (10. Sep 2012)

@SuppenGeist danke für die Antwort. Leider hillft mir auch deine Ausführung nich weiter. Bzgl. der Datenkapselung ist dies seitens des Play Frameworks so gewollt um u.a. den Quellcode übersichtlich zu halten, ist also nicht auf meinem Mist gewachsen ;-)

@tribalup was meinst du mit dem "template method pattern", ich konnte auf die schnelle nichts finden (play 1.2..5)


Gruß,
Bober


----------



## Marco13 (11. Sep 2012)

Ich kenne das "Play-Framework" nicht (und kann mir im Moment kaum vorstellen, dass das C-Like-Typabfragen-Antipattern, das weiter oben vorgeschlagen wurde, wirklich notwendig ist) aber... 



Bober hat gesagt.:


> ```
> public static <T extends Calculation> void run(T calculation, int t) {
> 
> calculation.calculate();
> ...



Das sollte an sich ja funktionieren... beschreib' ggf. nochmal genauer, was daran nicht passt...


----------



## Bober (11. Sep 2012)

@Marco13.
Seitens Java funktioniert dieses Konstrukt auch. das problem stellt hier das play framework dar. Deshalb ist es wohl besser ein neues thema mit entsprechendem namen zu eröffnen, da das problem kenntniss des frameworks verlangt.


----------



## phaus (11. Sep 2012)

Du vermengst hier meiner Meinung nach eine Model-Class ( Calculation ) mit Business Logic ( calculate() ).
Am saubersten bekommst Du das wohl gelöst, indem Du Deine Eingabe- und Ausgabewerte durch Key,Value Collections abbildest (z.B. HashMap). Eine Calculation könnte dann eine Value-Liste habe, die dann dynamisch Dein Formular aufbaut.

Diese Liste kannst Du dann direkt als Parameter für Deine Calculation verwenden.

Generell sollte man bei Play! einfache Wege gehen und vor allem möglichst wenig Status-behaftete Objekte verwenden.

@SuppenGeist Die Access-Methoden (Getter/Setter) werden von Play! zur Laufzeit generiert (und auch das Attribut wird nicht mehr public sein). Es dient alles dazu, den notwendigen Code für ein Model möglichst kompakt zu halten.


----------

