Noch mehr Java gibts auf www.javahochzwei.de

Schablone – Entwurfsmuster

Das Entwurfsmuster „Schablone“ bietet sich dann an, wenn man z.B. mehrere Algorithmen implementieren will, die aber gemeinsame Teile besitzen. Würde man diese Gemeinsamkeiten in jeden der verschiedenen Algorithmen einzeln schreiben, erhält man Redundanz. Die Wartungsfreundlichkeit und Übersichtlichkeit würde darunter sehr leiden. Stelle Dir vor, Du musst eine Änderung vornehmen, die alle Algorithmen betrifft. Nun musst Du Algorithmus für Algorithmus durchgehen und wehe Du vergisst einen.

Daher ist an dieser Stelle ganz klar das Entwurfsmuster „Schablone“ zu benutzen.

Um es an einem Beispiel nochmals zu verdeutlichen: Angenommen wir wollen ein Programm schreiben, bei dem man verschiedene Gesellschaftsspiele spielen kann. Unabhängig davon, welches Spiel vom späteren Benutzer gestartet wird, gibt es immer Gemeinsamkeiten: Lade Spielerdaten aus der Datenbank. Ist das Spiel zu Ende: Update die Spielerdaten in der Datenbank. Dies ist unabhängig davon, ob unser Benutzer nun gerade Schach, Mühle oder Karten gespielt hat! Auch hier wird klar: Wir brauchen das Schablone-Entwurfsmuster!

Wir müssen also alle Gemeinsamkeiten in eine einzige Klasse, bzw. Methode schreiben. Aber dennoch muss diese Methode verschiedene Verhaltensmuster (Schach, Mühle etc.) haben. Wie geht das?

Wir schreiben eine abstrakte Klasse Strategie. Hier können wir sowohl konkrete Methoden („normale Methoden“), als auch abstrakte Methoden (werden in der Hierarchie erst später definiert) definieren. In die konkrete Methode schreiben wir alle Gemeinsamkeiten der Algorithmen. Dort, wo von der Verhaltensweise Unterschiede bestehen, benutzen wir abstrakte Methoden, deren Verhalten erst später implementiert werden kann.

Jetzt wären schonmal die Gemeinsamkeiten implementiert. Nun fehlen aber noch „die Unterschiede“. Hierzu benötigen wir für jeden Algorithmus (Schach, Mühle etc.) eine eigene Klasse, die aber unsere abstrakte Klasse Strategie erweitert. In diesen „konkreten Unterklassen“ implementieren wir -wie gewohnt- die Funktionalität des jeweiligen Algorithmus (bzw. Spiels).

Codebeispiel:
Strategie.java:

package schablone;

/**
 * @author Armin
 * @since 12.09.2012
 * 
 * info@prog-blog.de
 * www.prog-blog.de
 */
public abstract class Strategie {

	public void algorithmusAusfuehren() {

		startAlgorithmus();		
		// abstrakt!
		konkreteHandlungsweise1();		
		waehrendAlgorithmus();		
		// abstrakt!
		konkreteHandlungsweise2();		
		endeAlgorithmus();	
	}

	public void startAlgorithmus() {
		// hier werden z.B. die zu bearbeitenden Daten geladen
		// dies passiert immer unabhängig der jeweiligen Strategie
		System.out.println("Der Algorithmus startet immer gleich!");
	}

	public abstract void konkreteHandlungsweise1();

	public void waehrendAlgorithmus() {
		System.out.println("Auch hier verhält sich der Algorithmus immer gleich!");
	}

	public abstract void konkreteHandlungsweise2();

	public void endeAlgorithmus() {
		// hier werden z.B. die erarbeiteten Daten gespeichert o.Ä.
		// dies passiert immer unabhängig der jeweiligen Strategie
		System.out.println("Das Ende ist auch immer das gleiche");
	}
}

KonkreteStrategie1.java:

package schablone;

/**
 * @author Armin
 * @since 12.09.2012
 * 
 * info@prog-blog.de
 * www.prog-blog.de
 */
public class KonkreteStrategie1 extends Strategie {

	@Override
	public void konkreteHandlungsweise1() {
		System.out.println("---> KonkreteStrategie1 - konkreteHandlungsweise1");
	}

	@Override
	public void konkreteHandlungsweise2() {
		System.out.println("---> KonkreteStrategie1 - konkreteHandlungsweise2");
	}
}

KonkreteStrategie2.java:

package schablone;

/**
 * @author Armin
 * @since 12.09.2012
 * 
 * info@prog-blog.de
 * www.prog-blog.de
 */
public class KonkreteStrategie2 extends Strategie {

	@Override
	public void konkreteHandlungsweise1() {
		System.out.println("---> KonkreteStrategie2 - konkreteHandlungsweise1");
	}

	@Override
	public void konkreteHandlungsweise2() {
		System.out.println("---> KonkreteStrategie2 - konkreteHandlungsweise2");
	}
}

Klient.java:

package schablone;

/**
 * @author Armin
 * @since 12.09.2012
 * 
 * info@prog-blog.de
 * www.prog-blog.de
 */
public class Klient {

	public static void main(String[] args) {

		Strategie strategie = new KonkreteStrategie1();
		strategie.algorithmusAusfuehren();

		System.out.println("----------");

		strategie = new KonkreteStrategie2();
		strategie.algorithmusAusfuehren();
	}
}

Führt man Klient.java aus, so erhält man als Ausgabe:

Der Algorithmus startet immer gleich!
---> KonkreteStrategie1 - konkreteHandlungsweise1
Auch hier verhält sich der Algorithmus immer gleich!
---> KonkreteStrategie1 - konkreteHandlungsweise2
Das Ende ist auch immer das gleiche
----------
Der Algorithmus startet immer gleich!
---> KonkreteStrategie2 - konkreteHandlungsweise1
Auch hier verhält sich der Algorithmus immer gleich!
---> KonkreteStrategie2 - konkreteHandlungsweise2
Das Ende ist auch immer das gleiche

 

Zu erwähnen wäre noch an dieser Stelle, dass man von abstrakten Klassen selbst kein Objekt erstellen kann. Dies ist aber nicht weiterschlimm, da wir das hier nicht brauchen.

Ein mögliches Szenario für unser Spieleprogramm wäre:

package schablone;

/**
 * @author Armin
 * @since 12.09.2012
 * 
 * info@prog-blog.de
 * www.prog-blog.de
 */
public class Klient {

	public static void main(String[] args) {

		Spiel spiel = new Schach();
		spiel.starten();

		// ist dieses Spiel vorbei und der Benutzer möchte das nächste spielen:

		spiel = new Muehle();
		spiel.starten();
	}
}

 

Quelltext herunterladen

  Strategie.rar (1,4 KiB, 62 hits)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.