Java - von Rias A. Sherzad am Dienstag, August 8, 2006 23:25 - 2 Kommentare
Factory Method Pattern in Java
Das Factory Method Pattern, die schreckliche deutsche Übersetzung lautet Fabrikmethode, stellt eine Schnittstelle für die Erzeugung eines Objekts bereit, überlässt aber die Entscheidung darüber, welche konkrete Klasse instanziiert werden soll, seinen Unterklassen. Das im folgenden aufgeführte Java-Beispiel beschreibt das Factory Method Pattern, wie es von der Gang of Four beschrieben wurde, anhand eines fiktiven Anwendungsfalles aus der Automobilbranche.
Zum leichteren Verständnis der Design Patterns möchte ich Ihnen den Bestseller Entwurfsmuster von Kopf bis Fuß nahelegen, welches die meiner Meinung nach verständlichste und beste Einführung in die Welt der Design Patterns bietet.
Kategorie
Das Factory Method Pattern wird zu den „Creational Patterns“ gezählt, da es Objekte erzeugt und zurückliefert.
Einsatzbereich
Das Factory Method Pattern kann eingesetzt werden, wenn:
- Die aufrufende Klasse nicht weiß, welche konkrete Klasse instanziiert werden soll.
- Die aufrufende Klasse nicht weiß, wie eine konkrete Klasse instanziiert werden muss.
- Die aufrufende Klasse Informationen zur Erzeugung einer Klasse mitgibt, anhand dieser das Factory Method Pattern entscheidet, welche konkrete Klasse instanziiert wird.
- Eine Klasse, die Verantwortung für die konkret zu erzeugende Klasse an ihre Unterklassen delegieren möchte.
UML-Klassendiagramm: Factory Method Pattern
Das UML-Klassendiagramm für das Factory Method Pattern sieht folgendermaßen aus:
Beispiel
In unserem stark vereinfachten Beispiel aus der Automobilbranche beginnen wir mit der abstrakten Klasse AbstrakterHersteller, die im UML-Klassenmodell die Klasse Creator repräsentiert. Sie hat einen Default-Constructor, also einen Constructor ohne Signatur, die als einzige Operation die Erzeugung von konkreten Fahrzeugen an abgeleitete Unterklassen delegiert, indem sie ihre abstrakte Methode erzeugeFahrzeuge() aufruft.
- package de.theserverside.designpatterns.factorymethod;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Stellt im UML-Klassendiagramm "Creator" dar, von der konkrete
- * Klassen abgeleitet werden, die auch instanziiert werden können.
- */
- public abstract class AbstrakterHersteller {
- protected List<abstraktesfahrzeug> fahrzeuge =
- new ArrayList<abstraktesfahrzeug>();</abstraktesfahrzeug></abstraktesfahrzeug>
- /**
- * Delegiert die Instanziierung der konkreten Fahrzeuge an
- * implementierende Unterklassen.
- *
- */
- public AbstrakterHersteller() {
- this.erzeugeFahrzeuge();
- }
- public List<abstraktesfahrzeug> getFahrzeuge() {
- return fahrzeuge;
- }</abstraktesfahrzeug>
- /**
- * Muss von einer Methode überschrieben werden, die konkrete
- * Fahrzeuge instanziiert. Dies ist das Herzstück des Factory
- * Method Pattern
- *
- */
- protected abstract void erzeugeFahrzeuge();
- }
Diese Klasse muss jetzt noch abgeleitet und die Implementierung der Methode erzeugeFahrzeuge() vervollständigt werden. Der Inhalt der Methode stellt die Verbindung namens „instantiates“ zwischen den Klassen ConcreteCreator und ConcreteProduct im UML-Klassendiagramm dar. Wir leiten AbstrakterHersteller im folgenden als Klasse BMW ab.
- package de.theserverside.designpatterns.factorymethod;
- /**
- * Stellt im UML-Klassendiagramm "ConcreteCreator" dar, die die
- * konkreten Klassen (ConcreteProduct) instanziiert.
- */
- public class BMW extends AbstrakterHersteller {
- /**
- * Implementiert die abstrakte Methode aus der Oberklasse
- * und erzeugt konkrete Fahrzeugobjekte
- */
- protected void erzeugeFahrzeuge() {
- fahrzeuge.add(new Z4(231));
- }
- }
Wir leiten AbstrakterHersteller ein zweites mal ab – dieses mal als Klasse Volkswagen.
- package de.theserverside.designpatterns.factorymethod;
- /**
- * Stellt im UML-Klassendiagramm "ConcreteCreator" dar, die die
- * konkreten Klassen (ConcreteProduct) instanziiert.
- */
- public class Volkswagen extends AbstrakterHersteller {
- /**
- * Implementiert die abstrakte Methode aus der Oberklasse
- * und erzeugt konkrete Fahrzeugobjekte
- */
- protected void erzeugeFahrzeuge() {
- fahrzeuge.add(new Passat(147));
- fahrzeuge.add(new Touareg(331));
- }
- }
Wie man sieht, erzeugen die beiden Implementierungen von AbstrakterHersteller neue Objekte, in unserem Fall Fahrzeugmodelle der jeweiligen Hersteller. All diese Fahrzeuge wiederum sind abgeleitet von AbstraktesFahrzeug, was im UML-Klassendiagramm der Klasse Product entspricht. Es ist zu beachten, daß die genaue Ausprägung der Klasse Product nicht der Definition des Factory Method Pattern unterworfen ist. Die folgende Implementierung ist also spezifisch für unser Beispiel.
- package de.theserverside.designpatterns.factorymethod;
- /**
- * Stellt im UML-Klassendiagramm "Product" dar, von der konkrete
- * Klassen abgeleitet werden, die auch instanziiert werden können.
- */
- public abstract class AbstraktesFahrzeug {
- private String hersteller;
- private String modell;
- private int kw;
- public String getHersteller() {
- return hersteller;
- }
- public String getModell() {
- return modell;
- }
- public int getKw() {
- return kw;
- }
- public AbstraktesFahrzeug(String hersteller, String modell,
- int kw) {
- this.hersteller = hersteller;
- this.modell = modell;
- this.kw = kw;
- }
- }
Es folgt der letzte Bestandteil des Factory Method Pattern, das ConcreteProduct. In unserem Fall sind das Fahrzeuge der beiden Automobilhersteller.
Der BMW Z4…
- package de.theserverside.designpatterns.factorymethod;
- /**
- * Stellt im UML-Klassendiagramm "ConcreteProduct" dar, die von
- * der Factory Methode instanziiert wird.
- */
- public class Z4 extends AbstraktesFahrzeug {
- public Z4(int kw) {
- super("BMW", "Z4", kw);
- }
- }
… ein Volkswagen Passat…
- package de.theserverside.designpatterns.factorymethod;
- /**
- * Stellt im UML-Klassendiagramm "ConcreteProduct" dar, die von
- * der Factory Methode instanziiert wird.
- */
- public class Passat extends AbstraktesFahrzeug {
- public Passat(int kw) {
- super("Volkswagen", "Passat", kw);
- }
- }
… und der Volkswagen Touareg.
- package de.theserverside.designpatterns.factorymethod;
- /**
- * Stellt im UML-Klassendiagramm "ConcreteProduct" dar, die von
- * der Factory Methode instanziiert wird.
- */
- public class Touareg extends AbstraktesFahrzeug {
- public Touareg(int kw) {
- super("Volkswagen", "Touareg", kw);
- }
- }
Die Implementierung dieses Beispiels dient nur der Anschaulichkeit. In einem realen Projekt würde man die Hierarchien anders abbilden und ggf. mit weniger Klassen auskommen. In unserem Beispiel müssten wir für jedes Fahrzeugmodell eine neue Klasse implementieren, was real natürlich nicht zielführend sein kann.
Um unsere Implementierung des Factory Method Pattern zu testen, dient folgende Klasse, die eine statische main(…)-Methode enthält, und damit als Anwendung aus der Konsole oder IDE gestartet werden kann.
- package de.theserverside.designpatterns.factorymethod;
- /**
- * Testet die Implementation des Factory Method Pattern
- */
- public class FactoryMethodMain {
- public static void main(String[] args) {
- /*
- * Hersteller Volkswagen und BMW instanziieren
- */
- AbstrakterHersteller vw = new Volkswagen();
- AbstrakterHersteller bmw = new BMW();
- /*
- * Ausgabe der Fahrzeuge eines jeden Herstellers
- */
- for (AbstraktesFahrzeug fahrzeug : vw.getFahrzeuge()) {
- System.out.println(
- fahrzeug.getHersteller() + " " +
- fahrzeug.getModell() + ", " +
- fahrzeug.getKw() + " KW");
- }
- for (AbstraktesFahrzeug fahrzeug : bmw.getFahrzeuge()) {
- System.out.println(
- fahrzeug.getHersteller() + " " +
- fahrzeug.getModell() + ", " +
- fahrzeug.getKw() + " KW");
- }
- }
- }
Wenn Sie diese Klasse starten, müssten Sie als Ausgabe folgende Zeilen auf der out-Konsole sehen:
Volkswagen Passat, 147 KW Volkswagen Touareg, 331 KW BMW Z4, 231 KW
Damit ist die Einführung in das Factory Method Pattern abgeschlossen. Sollten Sie Anregungen oder Verbesserungsvorschläge haben – oder Fehler im Code sehen – hinterlassen Sie hier gerne einen Kommentar.
Sourcecode zum Artikel
Sourcecode: Factory Method Pattern
Weiterführende Literatur
Wer sich mit Design Patterns näher auseinandersetzen will, kommt um das Standardwerk der „Gang of Four“ (GoF) „Design Patterns“ nicht herum. Der Link führt zur englischen Ausgabe des Buches, da die deutsche Übersetzung sehr grausam ist…
Wenn Ihnen dieses Buch zu trocken ist und Sie leichter verdaubares Material suchen, sind die beiden folgenden Bücher zum Thema „Design Patterns“, bzw. „Design Patterns in Java“ auch sehr zu empfehlen.
Eine unterhaltsame und sehr leicht verständliche Einführung in die Thematik Design Patterns in Java finden Sie mit „Entwurfsmuster von Kopf bis Fuß„. Das gesamte Buch ist bebildert und anschaulich gestaltet, und die Konzepte werden didaktisch hervorragend erläutert. Die Codebeispiele sind in Java geschrieben und auf das Nötigste reduziert.
Das Buch „The Design Patterns Java Workbook“ arbeitet die Design Patterns der Reihe nach ab, aber nicht, ohne vorher die Grundlagen (Interfaces, Abstrakte Klassen etc.) zu erläutern. Jedes Kapitel enthält Aufgaben, die gelöst werden können und anhand derer das Erlernte sofort praktisch angewandt werden kann. Da bisher keine deutsche Übersetzung existiert (Stand: August 2006), müssen Sie noch mit der englischen Fassung vorlieb nehmen.
2 Kommentare
Tobias Heckmann
keywan
Auch die Frage fast ein Jahr alt ist will ich mich mal dran versuchen:
Friends gibt es in Java ja nicht. Soll eine Klasse nur von einer bestimmten, verwaltenden Fabrikklasse erzeugt werden können bietet sich in Java eine inner Klasse an. Bei meinem Beispiel möchte ich aber auf abstrakte Klassen verzichten, ich bevorzuge Interfaces, in dem oben angeführten UML wären Creater und Product also Interfaces.
public class ConcreteFactory implements Creator{
public Product factoryMethod(){
return new ConcreteProduct();
}
public static class ConcreteProduct implements Product{
private ConcreteProduct(){
}
}
}
Kommentieren
Weitere Empfehlungen:
Java - Jul 19, 2011 20:30 - 0 Kommentare
Eine (wirklich gute) Einführung in Maven
Mehr Artikel der Kategorie Softwarearchitekturen
- Decorator Pattern in Java
- Cloud Computing mit Google App Engine und Java
- JMS mit Oracle Advanced Queueing
- Buchempfehlung: Service-orientierte Architekturen mit Web Services. Konzepte – Standards – Praxis
- Einführung in SOA – Serviceorientierte Architekturen
Datenbanken, Internet Technologien - Nov 19, 2009 9:24 - 0 Kommentare
Oracle WebServices im praktischen Einsatz
More In Datenbanken
- JMS mit Oracle Advanced Queueing
- Eine kurze Einführung in db4o
- Native Kompilierung von PL/SQL-Routinen in Oracle 10g
Eine Factory kann auch die Aufgabe haben, die Klassen, die sie produziert, verwaltet. Es sollte aus diesem Grund nicht von jedem Punkt im Programm aus möglich sein, eine bestimme Klasse zu initialisieren(ohne dies über die Factory zu tun). In C++ wird dies über das Attribut friend gemacht. Wie kann man so etwas in Java implementieren? Auf dies sollte in diesem Artikel eingegangen werden, da er sogar über Wikipedia verlinkt ist, und damit dem Anspruch auf Vollständigkeit gerecht werden sollte.