Java - von am Tuesday, August 8, 2006 23:25 - 3 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:

UML-Klassendiagramm: Factory Method Pattern

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.

  1. package de.theserverside.designpatterns.factorymethod;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. /**
  7.  * Stellt im UML-Klassendiagramm "Creator" dar, von der konkrete
  8.  * Klassen abgeleitet werden, die auch instanziiert werden können.
  9.  */
  10. public abstract class AbstrakterHersteller {
  11.     protected List<AbstraktesFahrzeug> fahrzeuge =
  12.         new ArrayList<AbstraktesFahrzeug>();
  13.    
  14.     /**
  15.      * Delegiert die Instanziierung der konkreten Fahrzeuge an
  16.      * implementierende Unterklassen.
  17.      *
  18.      */
  19.     public AbstrakterHersteller() {
  20.         this.erzeugeFahrzeuge();
  21.     }
  22.  
  23.     public List<AbstraktesFahrzeug> getFahrzeuge() {
  24.         return fahrzeuge;
  25.     }
  26.  
  27.     /**
  28.      * Muss von einer Methode überschrieben werden, die konkrete
  29.      * Fahrzeuge instanziiert. Dies ist das Herzstück des Factory
  30.      * Method Pattern
  31.      *
  32.      */
  33.     protected abstract void erzeugeFahrzeuge();
  34. }

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.

  1. package de.theserverside.designpatterns.factorymethod;
  2.  
  3. /**
  4.  * Stellt im UML-Klassendiagramm "ConcreteCreator" dar, die die
  5.  * konkreten Klassen (ConcreteProduct) instanziiert.
  6.  */
  7. public class BMW extends AbstrakterHersteller {
  8.     /**
  9.      * Implementiert die abstrakte Methode aus der Oberklasse
  10.      * und erzeugt konkrete Fahrzeugobjekte
  11.      */
  12.     protected void erzeugeFahrzeuge() {
  13.         fahrzeuge.add(new Z4(231));
  14.     }
  15. }

Wir leiten AbstrakterHersteller ein zweites mal ab – dieses mal als Klasse Volkswagen.

  1. package de.theserverside.designpatterns.factorymethod;
  2.  
  3. /**
  4.  * Stellt im UML-Klassendiagramm "ConcreteCreator" dar, die die
  5.  * konkreten Klassen (ConcreteProduct) instanziiert.
  6.  */
  7. public class Volkswagen extends AbstrakterHersteller {
  8.     /**
  9.      * Implementiert die abstrakte Methode aus der Oberklasse
  10.      * und erzeugt konkrete Fahrzeugobjekte
  11.      */
  12.     protected void erzeugeFahrzeuge() {
  13.         fahrzeuge.add(new Passat(147));
  14.         fahrzeuge.add(new Touareg(331));
  15.     }
  16. }

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.

  1. package de.theserverside.designpatterns.factorymethod;
  2.  
  3. /**
  4.  * Stellt im UML-Klassendiagramm "Product" dar, von der konkrete
  5.  * Klassen abgeleitet werden, die auch instanziiert werden können.
  6.  */
  7. public abstract class AbstraktesFahrzeug {
  8.     private String hersteller;
  9.     private String modell;
  10.     private int kw;
  11.  
  12.     public String getHersteller() {
  13.         return hersteller;
  14.     }
  15.  
  16.     public String getModell() {
  17.         return modell;
  18.     }
  19.     public int getKw() {
  20.         return kw;
  21.     }
  22.  
  23.     public AbstraktesFahrzeug(String hersteller, String modell,
  24.             int kw) {
  25.         this.hersteller = hersteller;
  26.         this.modell = modell;
  27.         this.kw = kw;
  28.     }
  29. }

Es folgt der letzte Bestandteil des Factory Method Pattern, das ConcreteProduct. In unserem Fall sind das Fahrzeuge der beiden Automobilhersteller.

Der BMW Z4…

  1. package de.theserverside.designpatterns.factorymethod;
  2.  
  3. /**
  4.  * Stellt im UML-Klassendiagramm "ConcreteProduct" dar, die von
  5.  * der Factory Methode instanziiert wird.
  6.  */
  7. public class Z4 extends AbstraktesFahrzeug {
  8.     public Z4(int kw) {
  9.         super("BMW", "Z4", kw);
  10.     }
  11. }

… ein Volkswagen Passat…

  1. package de.theserverside.designpatterns.factorymethod;
  2.  
  3. /**
  4.  * Stellt im UML-Klassendiagramm "ConcreteProduct" dar, die von
  5.  * der Factory Methode instanziiert wird.
  6.  */
  7. public class Passat extends AbstraktesFahrzeug {
  8.     public Passat(int kw) {
  9.         super("Volkswagen", "Passat", kw);
  10.     }
  11. }

… und der Volkswagen Touareg.

  1. package de.theserverside.designpatterns.factorymethod;
  2.  
  3. /**
  4.  * Stellt im UML-Klassendiagramm "ConcreteProduct" dar, die von
  5.  * der Factory Methode instanziiert wird.
  6.  */
  7. public class Touareg extends AbstraktesFahrzeug {
  8.     public Touareg(int kw) {
  9.         super("Volkswagen", "Touareg", kw);
  10.     }
  11. }

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.

  1. package de.theserverside.designpatterns.factorymethod;
  2.  
  3. /**
  4.  * Testet die Implementation des Factory Method Pattern
  5.  */
  6. public class FactoryMethodMain {
  7.  
  8.     public static void main(String[] args) {
  9.         /*
  10.          * Hersteller Volkswagen und BMW instanziieren
  11.          */
  12.         AbstrakterHersteller vw = new Volkswagen();
  13.         AbstrakterHersteller bmw = new BMW();
  14.        
  15.         /*
  16.          * Ausgabe der Fahrzeuge eines jeden Herstellers
  17.          */
  18.         for (AbstraktesFahrzeug fahrzeug : vw.getFahrzeuge()) {
  19.             System.out.println(
  20.                     fahrzeug.getHersteller() + " " +
  21.                     fahrzeug.getModell() + ", " +
  22.                     fahrzeug.getKw() + " KW");
  23.         }
  24.  
  25.         for (AbstraktesFahrzeug fahrzeug : bmw.getFahrzeuge()) {
  26.             System.out.println(
  27.                     fahrzeug.getHersteller() + " " +
  28.                     fahrzeug.getModell() + ", " +
  29.                     fahrzeug.getKw() + " KW");
  30.         }
  31.     }
  32. }

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.

Be Sociable, Share!


Kommentare

Kommentieren

Weitere Empfehlungen: