Das Factory Method Design Pattern

Studienprojekt von Philipp Hauer. 2009 - 2010. ©

Inhalt

Einführung

Ein Softwareshop verkauft vorranging Microsoft Office Applikationen, wie Word, Excel und Powerpoint. Wenn ein Kunde eine solche Applikation ordert, so sieht der entsprechende Code in der Verwaltungssoftware so aus:

Codeausschnitt aus der Verwaltungssoftware:

public class SoftwareShop { 

    public OfficeProgramm holeApp(String zuHolendesProg) { 
        OfficeProgramm programm = null; 
        //Auswahl der benötigten Applikation 
        if (zuHolendesProg.equals("Word")) { 
            programm = new Word(); 
        } 
        else if (zuHolendesProg.equals("Powerpoint")) { 
            programm = new Powerpoint(); 
        } 
        else if (zuHolendesProg.equals("Excel")) { 
            programm = new Excel(); 
        } 
        else { 
            System.err.println("Ungültig!"); 
        } 

        //Weitere Verarbeitung 
        programm.einpacken(); 
        programm.etikettieren(); 

        return programm; 
    } 
} 			
Schnittstelle OfficeProgramm und die Implementierungen Word, Powerpoint und Excel:

abstract class OfficeProgramm { 
    public void einpacken() {} 
    public void etikettieren() {} 
    public abstract void starten(); 
} 

class Word extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Word startet"); 
    } 
} 
class Powerpoint extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Powerpoint startet"); 
    } 
} 
class Excel extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Excel startet"); 
    } 
}			

Es wird die gewünschte Software ausgewählt, instanziiert, weiter bearbeitet (einpacken(), etikettieren()) und schließlich zurückgegeben. Dieser Entwurf hat allerdings eine Reihe von Nachteilen:

  • Geringe Kohäsion. Die Programminstanziierung und die weitere Verarbeitung werden zusammen durchgeführt.
  • Geringe Wiederverwendbarkeit. Was ist, wenn neue Klassen andere OfficeProgramme instanziieren wollen, den Verarbeitungscode allerdings wiederverwenden möchten?
  • Unser Offen/Geschlossen-Prinzip ist verletzt. Für Erweiterungen am Programmportfolio muss der bestehende Code geändert werden.

Um unseren Entwurf zu verbessern, rufen wir uns zwei alt bekannte OO-Entwurfsprinzipien ins Gedächtnis:

Offen/Geschlossen-Prinzip (Open/Closed):
Entwürfe sollten für Erweiterungen offen, aber für Veränderungen geschlossen sein.

Gemeint ist, dass Erweiterungen (neue OfficeProgramme etc.) ohne Änderungen an bestehenden Code in das System integriert werden können. Dies im Hinterkopf behaltend erinnern wir uns an ein weiteres stets aktuelles OO-Prinzip:

 Identifiziere jene Aspekte, die sich ändern und trenne sie von jenen, die konstant bleiben.

Veränderlich ist die Instanziierung von OfficeProgrammen. Konstant bleibt der weitere Verarbeitungsprozess danach (einpacken() und etikettieren()). Also liegt es nahe, die Logik zur OfficeProgrammerstellung in einer separaten Klasse zu kapseln - einer Factory.

Einleitung Factory Method Design Pattern

SoftwareShop:

class SoftwareShop { 
    OfficeProgramFactory officeProgFactory = new OfficeProgramFactory(); 

    public OfficeProgram holeApp(String zuHolendesProg) { 
        //Logik zur Auswahl des gewünschten Programms in Factory gekapselt. 
        OfficeProgram program = officeProgFactory.createOfficeProgram(zuHolendesProg); 

        //weitere verarbeitung 
        program.einpacken(); 
        program.etikettieren(); 

        return program; 
    } 
} 			
OfficeProgramFactory:

class OfficeProgramFactory { 
    public OfficeProgram createOfficeProgram(String zuHolendesProg) { 
        if (zuHolendesProg.equals("Word")) { 
            return new Word(); 
        } 
        else if (zuHolendesProg.equals("Powerpoint")) { 
            return new Powerpoint(); 
        } 
        else if (zuHolendesProg.equals("Excel")) { 
            return new Excel(); 
        } 
        else { 
            System.err.println("Ungültig!"); 
            return null; 
        } 
    } 
} 			

Die Factory - üblicherweise mit statischen Methoden - macht alleine aber noch kein Design Pattern. So nützlich sie auch ist, es handelt sich lediglich um ein Idiom. Nichtsdestotrotz haben wir nun eine Reihe von Missständen im alten Entwurf abgestellt.

  • Kohäsionsgewinn durch Trennung der Objekterstellung von der Objektverarbeitung.
  • Wiederverwendbarkeit der Factory.
  • Zentrale Stelle für Wartung und Erweiterung.

Doch was ist mit unserem Offen/Geschlossen-Prinzip? Sind wir nun für Erweiterungen offen? Was ist, wenn unser SoftwareShop nun noch weitere Office Suites neben Microsoft Office im Sortiment führen soll, beispielsweise Apple iWork oder Sun OpenOffice?

Unser Praktikant schlägt einen ungünstigen Entwurf vor: Dieser sieht für jede Suite eine eigene Factory vor, die durch den SoftwareShop genutzt wird.

Factory Method Design Pattern Einführung

Schon nicht schlecht, allerdings wird nun ein entscheidener Nachteil unseres Entwurfs deutlich: Die Objekteverarbeitung und die Objekterstellung sind nun zu stark entkoppelt! Denn nun ist es möglich die (public) Methode createOfficeProgramm() von der MicrosoftOfficeFactory (oder einer anderen Factory) direkt aufzurufen, und damit die notwendigen Verarbeitungsschritte der holeApp()-Methode des SoftwareShops zu umgehen. So kann Software unverpackt und unetikettiert an die Umwelt gelangen. Maximale Entkopplung ist hier nicht sinnvoll.

Wie können wir auf der einen Seite die Verarbeitung von der Herstellung trennen, sie aber trotzdem aneinander koppeln? Die Lösung liegt in der Vererbung und der Verwendung einer abstrakten Methode, die eine Subklasse implementieren muss. Diese abstrakte Methode ist die namensgebende Factory Method.

Dabei fungiert unserer SoftwareShop als abstrakte Superklasse. Sie enthält nun zwei Methoden: Zum einen die bekannte holeApp() und zum anderen definiert nun sie (nicht die Factorys) die Methode createOfficeProgram(), allerdings abstrakt. Diese Methode wird mit den Zugriffsmodifier protected der Umwelt unzugänglich gemacht.

Factory Method Design Pattern Einführung

Abstrakte Superklasse SoftwareShop:

public abstract class SoftwareShop { 

    public OfficeProgramm holeApp(String zuHolendesProg) { 
        //Delegation der Objekterstellung an Subklasse 
        OfficeProgramm programm = createOfficeProgram(zuHolendesProg); 

        //weitere verarbeitung 
        programm.einpacken(); 
        programm.etikettieren(); 

        return programm; 
    } 

    //Definition der Factory Method 
    protected abstract OfficeProgramm createOfficeProgram(String zuHolendesProg); 

}  			

Der SoftwareShop hat keine Ahnung, welches konkrete Programm er erhält. Dies entscheidet allein die Subklasse, denn diese muss die Factory Method createOfficeProgram() implementieren. Der SoftwareShop delegiert die Objektinstanziierung an seine Subklasse. Von außen ist diese Methode unsichtbar (Zugriff protected). Somit wird gewährleistet, dass der Verarbeitungsprozess immer durchgeführt wird.

Die Subklassen erweitern SoftwareShop und implementieren die Factory Method, wobei sie natürlich ihre speziellen Programme je nach Hersteller zurückgeben.

Die Subklassen MicrosoftOfficeFactory, AppleiWorkFactory, SunOpenOfficeFactory instanziieren ihre Programme und geben sie zurück:

class MicrosoftOfficeFactory extends SoftwareShop{ 
    @Override 
    protected OfficeProgramm createOfficeProgram(String zuHolendesProg) { 
        OfficeProgramm programm = null; 
        if (zuHolendesProg.equals("Textverarbeitung")) { 
            programm = new Word(); 
        } 
        else if (zuHolendesProg.equals("Präsentation")) { 
            programm = new Powerpoint(); 
        } 
        else if (zuHolendesProg.equals("Tabellenkalkulation")) { 
            programm = new Excel(); 
        } 
        else { 
            System.err.println("Ungültig!"); 
        } 
        return programm; 
    } 
} 
class AppleiWorkFactory extends SoftwareShop{ 
    @Override 
    protected OfficeProgramm createOfficeProgram(String zuHolendesProg) { 
        OfficeProgramm programm = null; 
        if (zuHolendesProg.equals("Textverarbeitung")) { 
            programm = new Pages(); 
        } 
        else if (zuHolendesProg.equals("Präsentation")) { 
            programm = new Keynode(); 
        } 
        else if (zuHolendesProg.equals("Tabellenkalkulation")) { 
            programm = new Numbers(); 
        } 
        else { 
            System.err.println("Ungültig!"); 
        } 
        return programm; 
    } 
} 
class SunOpenOfficeFactory extends SoftwareShop{ 
    @Override 
    protected OfficeProgramm createOfficeProgram(String zuHolendesProg) { 
        OfficeProgramm programm = null; 
        if (zuHolendesProg.equals("Textverarbeitung")) { 
            programm = new Write(); 
        } 
        else if (zuHolendesProg.equals("Präsentation")) { 
            programm = new Impress(); 
        } 
        else if (zuHolendesProg.equals("Tabellenkalkulation")) { 
            programm = new Calc(); 
        } 
        else { 
            System.err.println("Ungültig!"); 
        } 
        return programm; 
    } 
} 			
Die OfficeProgramme der verschiedenen Hersteller:

abstract class OfficeProgramm { 
    public void einpacken() {} 
    public void etikettieren() {} 
    public abstract void starten(); 
} 

class Word extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Word startet"); 
    } 
} 
class Powerpoint extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Powerpoint startet"); 
    } 
} 
class Excel extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Excel startet"); 
    } 
} 
class Pages extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Pages startet"); 
    } 
} 
class Keynode extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Keynode startet"); 
    } 
} 
class Numbers extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Numbers startet"); 
    } 
} 
class Write extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Write startet"); 
    } 
} 
class Impress extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Impress startet"); 
    } 
} 
class Calc extends OfficeProgramm { 
    public void starten() { 
        System.out.println("Calc startet"); 
    } 
} 			

Der Client instanziiert die gewünschte HerstellerFactory und kann sich von dieser fortan Programme über die Methode der Superklasse holen. Er arbeitet nur gegen die Schnittstellen (SoftwareShop, OfficeProgramm) und weiß damit nicht, mit welchen konkreten Produkten er arbeitet.

Beispielclient:

public class Client{ 
    public static void main(String[] args) { 
        SoftwareShop appleShop = new AppleiWorkFactory(); 
        OfficeProgramm appleTextProgram = appleShop.holeApp("Textverarbeitung"); 
        appleTextProgram.starten();//"Pages startet" 

        SoftwareShop msShop = new MicrosoftOfficeFactory(); 
        OfficeProgramm wordPresProgram = msShop.holeApp("Präsentation"); 
        wordPresProgram.starten();//"Powerpoint startet" 
    } 
} 			

In der Zusammenschau ergibt sich die finale Modellierung unseres ShopSystems. Sehr schön zeigt sich die Entsprechung der beiden Vererbungshierarchien von Program und SoftwareShop: Der abstrakte SoftwareShop kennt nur das ebenso abstrakte OfficeProgram. Die konkreten Subklassen kennen hingegen die konkreten Programme.

Factory Method Entwurfsmuster

Zu den Vorteilen, die uns der Einsatz der "normalen" Factory brachte, kommen nun dank Factoy Method Pattern weitere:

  • Wiederverwendbarkeit durch Entkopplung der Objektverarbeitung von einer konkreten Implementierung. Die Verarbeitung kennt nur die Schnittstelle. Sie kann damit jedes beliebige Programm verarbeiten. Neue Programme sind schnell integriert, da der Verarbeitungscode wiederverwendet werden kann.
  • Konsistenz durch die Zentralisierung der Verarbeitung und die Unumgänglichkeit dieses Schrittes. Der Verarbeitungsprozess kann nun an einer zentralen Stelle gewartet und erweitert werden. Weiterhin kann kein unverarbeitetes Programm mehr an den Client gehen.
  • Erweiterbarkeit. Neue OfficeSuites können ins System integriert werden ohne bestehenden Code verändern zu müssen. Zur Erweiterung bedarf es lediglich der Ableitung des SoftwareShops. Das Offen/Geschlossen-Prinzip wurde realisiert.

Es zeigt sich, dass durch den Einsatz des Factory Method Patterns, ein hohes Maß an Flexibilität und Allgemeingültigkeit gewonnen wird, während zeitgleich die Wartung erleichtert wurde und Erweiterungen schnell und unkompliziert möglich sind.

Nach dieser Einführung wird im folgenden Abschnitt das Factory Method Design Pattern formalisiert, näher analysiert und diskutiert.

Das OfficeProgrammbeispiel mit Factory Method Pattern Termini

Klasse Factory Method Teilnehmer
abstrakter SoftwareShop Creator
konkrete OfficeSuiteFactorys ConcreteCreator
abstrakte OfficeProgram-Schnittstelle Product
konkrete Programme ConcreteProduct

Exkurs: Dependency Inversion Prinzip

(frei nach [VKBF], Seite 137 ff.)

Das Factory Method Pattern ermöglicht die Einhaltung des Dependency Inversion Prinzips, dem Prinzip der Abhängigkeitsumkehrung. Zugrunde liegt folgendes OO-Entwurfsprinzip:

Stütze dich nie auf eine konkrete Klasse, sondern immer auf Abstraktion - und das beidseitig.

Bei diesem Prinzip handelt es sich um eine konsequente Weiterentwicklung unseres "Programmiere immer auf eine Schnittstelle"-Entwurfsprinzips. Es gilt immer mit Abstraktionen zu arbeiten und das nicht von der hochschichtigen Komponenten zur tiefschichtigen Komponenten, sondern auch anders rum: von tiefschichtigen Komponenten zu hochschichtigen Komponenten. Denken wir an unseren SoftwareShop:

Dependency Inversion Principle - Prinzip der Abhängigkeitsumkehrung Dependency Inversion Principle - Prinzip der Abhängigkeitsumkehrung

In unseren ursprünglichen Entwurf kümmerte sich der SoftwareShop selbst um die Instanziierung der konkreten OfficeProgramme. Er war damit abhängig von konkreten, tiefschichtigen Komponenten. Jede Änderung am OfficeProgrammportfolio würde eine Änderung des SoftwareShops - einer hohen Komponente - nach sich ziehen.

Im finalen Entwurf kennt der SoftwareShop nur die Abstraktion OfficeProgramm und ist damit von den konkreten Klassen entkoppelt.

Gleiches gilt für die konkreten Programme: Sie haben zwar an Abhängigkeit gewonnen, sind aber nur von der Abstraktion OfficeProgramm abhängig, da sie diese Klasse erweitern. Und genau an diesem Punkt hat sich die Abhängigkeit umgekehrt.

Alle Komponenten - sowohl die der hohen Schicht (SoftwareShop), als auch die der tiefen (Konkrete Programme) - stützen sich gleichermaßen auf eine Abstraktion. Dank dieser Schnittstelle ist die hohe Komponente unabhängig von den tiefen Komponenten und umgekehrt.

Das ist das Dependency-Inversion-Prinzip.

Analyse und Diskussion

Gang Of Four-Definition

Factory Method:
"Definiere eine Klassenschnittstelle mit Operationen zum Erzeugen eines Objekts, aber lasse Unterklassen entscheiden, von welcher Klasse das zu erzeugende Objekt ist. Fabrikmethoden ermöglichen es einer Klasse, die Erzeugung von Objekten an Unterklassen zu delegieren."
([GoF], Seite 131)

Beschreibung

Factory Method Schema

Das Factory Method Entwurfsmuster dient der Entkopplung des Clients von der konkreten Instanziierung einer Klasse. Das erstellte Objekt kann elegant ausgetauscht werden. Oft wird es zur Trennung von (zentraler) Objektverarbeitung und (individueller) Objektherstellung verwendet.

Der Erstellungscode eines Objektes (Product genannt) wird in einer eigenen Klasse (Creator, Factory) ausgelagert. Dieser Creator ist abstrakt und delegiert die konkrete Objektinstanziierung wiederrum an seiner Unterklasse. Erst die Unterklasse entscheidet welches Product erstellt wird. Da der Client sich komplett auf Abstraktion stützt (sowohl beim Creator als auch bei den Products), ist er vollkommen von den Implementierungen entkoppelt und unabhängig.

Der Creator ist abstrakt, und kennt nur die abstrakte Schnittstelle vom Product und instanziiert nicht ein konkretes Productobjekt, sondern lässt seine Unterklassen entscheiden, welches konkrete Product erzeugt werden soll. Dazu definiert es eine abstrakte Methode (die namensgebende factoryMethod()), die es in seiner createProduct()-Methode aufruft und die seine Unterklassen implementieren müssen. Unterklassen (ConcreateCreators) implementieren diese Methode und geben ein ConcreteProduct zurück.

Nachdem die Unterklasse des Creators das konkrete Product an den Creator zurückgegeben hat, kann der Creator noch allgemeinen Herstellungscode enthalten, die auf jedes Product angewandt werden muss, bevor es an den Client geliefert wird.

Der Creator kann beliebig erweitert werden (ConcreteCreatorB, ConcreateCreatorC) und somit verschiedene Products liefern.

Factory Method Beschreibung

Abstrakter Creator und konkreter Creator A und B:

public abstract class Creator { 

    public Product createProduct() { 
        //holt konkretes Product, weiß nicht welches. 
        Product product = factoryMethod(); 

        //allgemeiner Productherstellungscode 
        product.setState(23); 
        product.prepare(); 
        return product; 
    } 

    protected abstract Product factoryMethod(); 
} 

class ConcreteCreatorA extends Creator { 

    protected Product factoryMethod() { 
        ConcreteProductA concProd = new ConcreteProductA(); 
        //ggf. noch das ConcreateProductA bearbeiten... 
        return concProd; 
    } 
} 

class ConcreteCreatorB extends Creator { 

    protected Product factoryMethod() { 
        ConcreteProductB concProd = new ConcreteProductB(); 
        //ggf. noch das ConcreateProductB bearbeiten... 
        return concProd; 
    } 
} 			
Abstraktes Product und konkrete Products A und B:

public abstract class Product { 

    private int basisState; 

    public void prepare() { 
        System.out.println("preparing general Product"); 
    } 

    public void setState(int state) { 
        this.basisState = state; 
    } 

    public int getState() { 
        return basisState; 
    } 

    public abstract int getPrice(); 
    //further code 
} 

class ConcreteProductA extends Product { 

    @Override 
    public int getPrice() { 
        return 1400; 
    } 
    //further code 
} 

class ConcreteProductB extends Product { 

    @Override 
    public int getPrice() { 
        return 2200; 
    } 
    //further code 
} 

class ConcreteProductC extends Product { 

    @Override 
    public int getPrice() { 
        return 800; 
    } 
    //further code 
} 			
Beispielclient:

public class Client { 
    public static void main(String[] args) { 
        Creator creator = new ConcreteCreatorA(); 
        Product product = creator.createProduct(); 
        System.out.println(product.getPrice()); 
    } 
} 			

Variationen

Creator enthält Defaultimplementierung

Statt den Creator und seine Fabrikmethode abstrakt zu definieren, und somit die Unterklassenbildung zu erzwingen, kann der Creator konkret sein und eine Defaultimplementierung für die Fabrikmethode enthalten. Unterklassen können diese Fabrikmethode überschreiben. Dadurch wird die gesamte Unterklassenbildung optional und die Fabrikmethode wird nur aus Flexibilitätsgründen genutzt, um die Objekterstellung in einer separaten Methode zu kapseln, die dann von Unterklassen ggf. überschrieben werden kann.

Parametrisierte Fabrikmethoden

Die Fabrikmethode bzw. die nach außen sichtbare Methode zur Herstellung eines Products (createProduct()) kann parametrisiert sein. Dadurch können dem Creator Informationen mitgegeben werden, welches konkrete Product er erstellen soll:

Anhand des Parameters wird entschieden, welches Produkt instanziiert werden soll:

public Werkzeug createWerkzeug(String werkzeug){ 
    if (werkzeug.equals("Zange")){ 
        return new Zange(); 
    } else if (werkzeug.equals("Knochen")){ 
        return new Knochen(); 
    } else if (werkzeug.equals("Schlüssel")){ 
        return new Schluessel(); 
    } else { 
        return null; 
    } 
} 			

Der Vorteil hierbei ist, dass schnell und unkompliziert neue Produkte hinzugefügt und ausgetauscht werden können.

Die Alternative ist eine Fabrikmethode ohne Parameter, sodass jeder ConcreteCreator genau ein Produkt herstellen kann. Für weitere Produkte müssen neue Unterklassen von Creator gebildet werden. Dies kann sinnvoll sein, wenn eine geringe Anzahl von Produkten hergestellt werden soll, der Erstellungsprozess allerdings umfangreicher und produktspezifischer ist.

Ein ConcreteCreator erzeugt genau ein Product:

abstract class Autowerkstatt { 
    public Auto getMercedes(){ 
        Auto auto = createMercedes(); 
        auto.testFahren(); 
        auto.waschen(); 
        auto.ausliefern(); 
        return auto; 
    } 
    protected abstract Auto createMercedes(); 
} 

class MercedesAutowerkstatt extends Autowerkstatt{ 
    @Override 
    protected Auto createMercedes() { 
        Mercedes mercedes = new Mercedes(); 
        //produktspezifische Erstellung 
        mercedes.setMercedesStern(); 
        mercedes.superLackieren(); 
        return mercedes; 
    } 
}			

Anwendungsfälle

  • Trennung der Objektverarbeitung (Wie?) von der konkreten Objekterstellung (Instanziierung; Was?). Delegation der Objektinstanziierung an Unterklasse.
    • Authentifizierungssysteme. Für jeden User wird nach dem Login ein Ticket erstellt, das seine Rechte im System repräsentiert. Statt eine universelle Ticketklasse mit duzenden, je nach Userrechten gesetzten Attributen zu nutzen, werden spezielle Tickets erstellt. Dies geschieht mittels einer TicketFactory und einer createTicket()-Methode, die mit den nötigen Informationen parametrisiert wird. Anhand dieser Parameter wird entschieden, welches Ticket erstellt wird. Verschiedene Erzeugungsprozesse werden durch mehrfaches Ableiten dieser Factory ermöglicht (InternetTicketFactory, IntranetTicketFactory). ([PK], Seite 27f.)
  • Fälle, in denen mit einer wachsenden Anzahl und Ausformung von Produkten zu rechnen ist. Sowie Szenarien in denen alle Produkte einen allgemeinen Herstellungsprozess durchlaufen müssen, egal was für ein Produkt sie konkret sind.
    • Eine Pizzeria erstellt je nach Parameter verschiedene Pizzen (Salami, Hawaii, Calzone, Quattro Stagioni), die immer gleich zubereitet werden (backen, schneiden, einpacken). Um den regionalen Wünschen der Menschen in Berlin, Hamburg und Rostock zu genügen, müssen spezielle Pizzen für eben diese Städte erstellt werden. Diese Erstellung geschieht in den speziellen Unterklassen der Pizzeria (BerlinPizzeria, HamburgPizzeria, RostockPizzeria), die die speziellen Pizzen erstellen (BerlinSalami, RostockCalzone etc.). Die Verarbeitung ist in allen Fällen gleich und erfolgt in der abstrakten Pizzeriaklasse, die nur die abstrahierte Pizzaschnittstelle kennt. Schnell können somit neue Pizzasorten und Pizzerias ins System integriert werden. ([VKBF], Seite 118ff.)
  • Wenn die konkret zu erstellenden Produkte nicht bekannt sind oder nicht von vorne herein festgelegt werden sollen.
    • Frameworks und Klassenbibliotheken.

Vorteile

  • Herstellungsprozess ist von einer konkreten Implementierung getrennt und unterschiedliche Produktimplementierungen können denselben Produktionsvorgang durchlaufen.
  • Wiederverwendbarkeit und Konsistenz durch
    • Kapselung des Objekterstellungscodes in eigener Klasse. Dadurch entsteht eine einheitliche und zentrale Schnittstelle für den Client. Die Produktimplementierung ist von seiner Verwendung entkoppelt. Außerdem entsteht ein zentraler Punkt der Wartung (geringerer Änderungsaufwand).
    • Kapselung des allgemeinen Herstellungscodes in die Superklasse Creator, die auf jedem Produkt vor Auslieferung an den Client durchgeführt wird.
  • Erweiterbarkeit, Austauschbarkeit und Flexibilität durch problemlose Einführung neuer Products und ConcreteCreators (bzw. Modifizierung oder Auswechseln bestehender) ohne Brechen des Clientcodes, dank konsistenter Schnittstelle. So kann ein neuer ConcreteCreator in das System integriert werden und dabei bestehenden Creatorcode wiederverwenden ohne Änderungen am bestehenden Client nötig zu machen.

Nachteile

  • Enge Kopplung eines konkreten Creators an ein konkretes Produkt. Für jedes neue Produkt muss ein neuer ConcreteCreator geschrieben werden und den abstrakte Creator ableiten. Unser Gesamtsystem hat damit nur wegen der Fabrikmethode einen weiteren Evolutionsast. Bei der parametrisierten Variante des Patterns ist dies weniger problematisch, da oft nur ein bestehender konkreter Creator angepasst werden muss.

Exkurs

Der Vergleich von Factory Method mit dem Abstract Factory Pattern wird im Artikel zur Abstract Factory durchgeführt.