Template Methode
Coderefaktoring
davor
Eine Anweisung Kaffee bzw. Tee zu kochen könnte folgende Form besitzt.- Bedienungsanleitung
Koche das Wasser
Gib das Kaffeepulver in die Tasse
Giesse das Wasser auf
Füge den Zucker hinzu
Rühre um
----------------------
Koche das Wasser
Gib den Teebeutel in die Tasse
Giesse das Wasser auf
Füge die Milch hinzu
Rühre um
- Haupprogramm
import templateFirst.Kaffee;
import templateFirst.Tee;
public class templateFirst {
public static void main(String[] args) {
Kaffee kaffee = new Kaffee();
Tee tee = new Tee();
kaffee.kaffeeKochenAnleitung();
System.out.println("----------------------");
tee.anleitung();
}
}
- Kaffee Klasse
package templateFirst;
public class Kaffee {
public void kaffeeKochenAnleitung(){
wasserKochen();
kaffeepulverHinzufügen();
wasserAufgiessen();
zuckerHinzufügen();
rühreUm();
}
protected void wasserKochen(){
System.out.println("Koche das Wasser");
}
protected void kaffeepulverHinzufügen(){
System.out.println("Gib das Kaffeepulver in die Tasse");
}
protected void wasserAufgiessen(){
System.out.println("Giesse das Wasser auf");
}
protected void zuckerHinzufügen(){
System.out.println("Füge den Zucker hinzu");
}
protected void rühreUm(){
System.out.println("Rühre um");
}
- Tee Klasse
package templateFirst;
public class Tee {
public void anleitung(){
wasserKochen();
teeBeutelHinzufügen();
wasserAufgiessen();
milchHinzufügen();
rühreUm();
}
protected void wasserKochen(){
System.out.println("Koche das Wasser");
}
protected void teeBeutelHinzufügen(){
System.out.println("Gib den Teebeutel in die Tasse");
}
protected void wasserAufgiessen(){
System.out.println("Giesse das Wasser auf");
}
protected void milchHinzufügen(){
System.out.println("Füge die Milch hinzu");
}
protected void rühreUm(){
System.out.println("Rühre um");
}
- erster Ansatz:
- das Klassendiagramm zeigt das Problem noch schöner: Coderedundanz
- um in der Ausdrucksweise von ExtremeProgramming zu bleiben: the code smells
danach
Ich wähle dazu folgende Vorgehensweise:- alle ähnlichen Methoden sollen den gleichen Namen erhalten
- führe eine abstrake Basisklasse ein
- Methoden, die identisch sind, ziehe ich in die Basisklasse
- Methoden, die eine Varianz des Verhalten darstellen, lege ich als abstrakte Methoden in der Basisklasse an
- die Funktionalität erhalten bleibt
- nach jedem Schritt ein Test das Refaktorieren validiert
- Applikation
import templateSecond.Coffeein;
import templateSecond.Kaffee;
import templateSecond.Tee;
public class templateSecond {
public static void main(String[] args) {
Coffeein kaffee = new Kaffee();
Coffeein tee = new Tee();
kaffee.anleitung();
System.out.println("----------------------");
tee.anleitung();
}
- Basisklasse Coffeein
package templateSecond;
public abstract class Coffeein {
public void anleitung(){
wasserKochen();
coffeeinHinzufügen();
wasserAufgiessen();
zutatHinzufügen();
rühreUm();
}
protected void wasserKochen() {
System.out.println("Koche das Wasser");
}
protected void wasserAufgiessen() {
System.out.println("Giesse das Wasser auf");
}
protected void rühreUm() {
System.out.println("Rühre um");
}
protected abstract void coffeeinHinzufügen();
protected abstract void zutatHinzufügen();
}
- Klasse Tee
package templateSecond;
public class Tee extends Coffeein {
protected void coffeeinHinzufügen(){
System.out.println("Gib den Teebeutel in die Tasse");
}
protected void zutatHinzufügen(){
System.out.println("Füge die Milch hinzu");
}
- Klasse Kaffee
package templateSecond;
public class Kaffee extends Coffeein {
protected void coffeeinHinzufügen(){
System.out.println("Gib das Kaffeepulver in die Tasse");
}
protected void zutatHinzufügen(){
System.out.println("Füge den Zucker hinzu");
}
- die deutlich verbesserte Struktur kann man gut am Klassendiagramm sehen
Nutzen:
- legt die Struktur eines Algorithmus in der Basisklasse fest und delegiere einzelne Schritte an Unterklassen
- unterstützt die Wiederverwendung von Methoden durch die Identifizierung der variablen und konstanten Komponenten des Algorithmuses
- fördert die leichte Erweiterbarkeit von bestehenden Klassenhierachien, da lediglich die virtuelle Methoden in neuen Unterklassen überschrieben werden müssen um den Algorithmus richtig zu prozessieren
- ist ein mächtiges Mittel gegen copy and paste Codierung
Auch bekannt als
- Schablonenmethode
Variante
In der Sprache C++ ist dies Pattern auch als Non Virtual Interface (NVI) bekannt, da hier eine öffentliche, nicht virtuelle Methode die Struktur des Alogrithmus vorgibt und private bzw. protected virtuelle Methoden die Funktionalität implementieren.Durch die Trennung von Interface ( öffentliche, nicht virtuelle Methode ) und Implementierung ( protected oder private virtuelle Methode ) gibt gerade Non Virtual Interface ein stabiles Interface vor, das nur Variation auf den virtuellen Methoden erlaubt.
Weiterlesen...