(Credits: Blog von Vishal Chovatiya)
„Erstellung von Objekten auf Basis einer Schnittstelle in einer Oberklasse, die es den Unterklassen erlaubt, den Typ der zu erstellenden Objekte zu konkretisieren.”
Das Factory Method Pattern ist ein Entwurfsmuster, mit dem Objekte erstellt werden können, ohne den Objekttyp anzugeben, der hierzu verwendet werden soll. Das Entwurfsmuster definiert zuallererst eine Methode, die ein Objekt erzeugt. Welche Klasse hierbei herangezogen wird, entscheidet die konkrete Klasse, die diese Methode implementiert.
Zum Erstellen des Objekts wird eine Schnittstelle benötigt. Die Unterklassen entscheiden, welche Klasse instanziiert werden soll. Mit dem Factory Method Pattern kann eine Klasse die Instanziierung auf Unterklassen verschieben.
Konsequenz:
- Factory Methoden verhindern, dass anwendungsspezifische Klassen in der Anwendung in Erscheinung treten.
- Das Factory Method Pattern ermöglicht es dem Clientcode, mit abstrakten Klassen und Schnittstellen zu arbeiten, ohne die konkreten Klassen zu kennen, die diese Schnittstellen implementieren. Dies fördert eine lose Kopplung und macht den Code flexibler und erweiterbar.
Das Factory-Entwurfsmuster definiert eine Schnittstelle zum Erstellen eines Objekts und überlässt die Auswahl des konkreten Klassentyps den Unterklassen. Das Entwurfsmuster macht ein Software-Design leichter anpassbar und weniger abhängig von anderen Klassen.
In dem Muster kommen zwei Vererbungshierarchien vor: eine mit den Factory-Klassen und eine zweite mit den zu erzeugenden Objekten. Diese werden in dem Muster häufig als Produkte bezeichnet.
Das folgende UML-Diagramm beschreibt eine Implementierung des Factory Method Patterns. Es besteht im Wesentlichen aus vier Teilen:
- FactoryBase: Abstrakte Klasse (oder Schnittstelle) für konkrete Factory-Klassen,
die die gesuchten Objekte erzeugen.
Wichtigste Aufgabe dieser Klasse ist die Bereitstellung (Definition) der Fabrikmethode:
Die Signatur der Methode
requestProductwird festgelegt, dieProductBase-Objekte zurückliefert. - ConcreteFactory: Repräsentiert eine konkrete Umsetzung der
FactoryBase-Klasse. Normalerweise überschreibt diese Klasse eine private, virtuelle MemberfunktioncreateProduct(), die vonProductBaseabgeleitete Objekte zurück gibt. - ProductBase: Basisklasse (oder Schnittstelle) für alle Produkte, die von konkreten Factory-Klassen hergestellt werden.
- ConcreteProduct: Konkrete Implementierung der Klasse
ProductBase. Einfacher formuliert: Eine Klasse für ein konkret zu erstellendes Produkt. KonkreteProductBase-Klassen sollten produktspezifische Funktionalitäten enthalten. Objekte des TypsConcreteProductwerden von Methoden der Factory-Klassen erstellt.
Abbildung 1: Schematische Darstellung des Factory Method Patterns.
Bemerkung:
Die FactoryBase-Basisklasse ist interessant in Bezug auf ihren Entwurf:
Wenn die öffentliche, nicht-virtuelle Memberfunktion requestProduct() aufgerufen wird,
ruft diese intern die private, virtuelle Memberfunktion createProduct() auf,
die ein neues konkretes Produkt erstellt und zurückgibt.
Dieses Idiom wird auch als nicht-virtuelles Schnittstellenidiom (NVI) bezeichnet.
Die Idee dahinter ist, dass einzelne Fabriken createProduct() überschreiben,
um ein Objekt eines entsprechenden Produkttyps zurückzugeben.
Die FactoryBase-Basisklasse selbst implementiert eine Methode requestProduct(),
die sich nebenbei noch um andere Dinge kümmern kann,
wie zum Beispiel die Anzahl der produzierten Produkte zu verwalten.
Die Memberfunktion requestProduct() ist ein Beispiel für das
Template Method Entwurfsmuster.
Die Memberfunktion createProduct() ist ein Beispiel für das
Virtual Constructor Entwurfsmuster (auch als Prototype Entwurfsmuster bezeichnet).
Der Begriff „Factory (Fabrik)” tritt in der Software als auch in der Literatur etwas inflationär in Erscheinung. Nicht immer wird dieses Konzept einheitlich verwendet.
Das „Factory Method Pattern” definiert zuallererst eine Methode, die ein Objekt erzeugt. Von welchem Klassentyp dieses Objekt ist, entscheidet die konkrete Klasse, die diese Methode implementiert.
Es gibt also zwei Vererbungshierarchien:
- eine mit den Factory-Klassen.
- eine zweite mit den zu erzeugenden Objekten (wir bezeichnen sie als Produkte).
Quellcode 1 – Einfaches Beispiel.
Quellcode 2 – Erweiterung des einfachen Beispiels um eine Fabrik mit Lastausgleich.
Quellcode 3 – Beispiel zu heißen Getränken.
Jeder Container der Standard Template Library verfügt über acht Factory-Funktionen zum Generieren verschiedener Iteratoren.
begin,cbegin: Gibt einen Iterator bzgl. des Anfangs des Containers zurück.end,cend: Gibt einen Iterator bzgl. des Endes des Containers zurück.rbegin,crbegin: Gibt einen Reverse-Iterator bzgl. des Anfangs des Containers zurück.rend,crend: Gibt einen Reverse-Iterator bzgl. des Endes des Containers zurück.
Die mit c beginnenden Fabrikfunktionen geben konstante Iteratoren zurück.
Quellcode - Real-World-Beispiel (ITelevision), das exemplarisch mehrere Factory Methods betrachtet.
Im „Real-World” Beispiel finden Sie ein Programm
mit den Klassen ITelevision, LEDTelevision, OledTelevision, AbstractTVFactory, LEDTVFactory und OledTVFactory vor.
Studieren Sie die Methoden manufactureTelevision, assembleTelevision, shippingCharge
und productionCharge der Klasse AbstractTVFactory.
Beschreiben Sie, wie diese Methoden zur Namensgebung des Factory Method Patterns beitragen.
Abbildung 2: Das Factory Method Pattern am Beispiel der Produktion von Fernsehgeräten.
Die beiden Entwurfsmuster Simple Factory und Factory Method sind nicht miteinander zu verwechseln.
Simple Factory
- Mit dem Simple Factory Pattern versuchen wir, die Details in der Erstellung eines Objekts vor dem Aufrufer (Client) zu abstrahieren. Das einzige, was der Client weiß, indem er eine Methode aufruft und den gewünschten Parameter übergibt, ist, dass er ein Objekt eines bestimmten Typs erhält. Aber wie dieses Objekt erstellt wird, weiß der Client-Code nicht.
Factory Method
- Das Factory Method Pattern bietet sich an, wenn die Anforderungen an die Erstellung eines Objekts mehr als nur der Aufruf des
new-Operators sind. Sind zur Erzeugung des Objekts mehrere Schritte notwendig, möchte man diese Schritte ggf. anpassen können oder sind diese Schritte bei verschiedenen Objekten unterschiedlich, verwendet man das Factory Method Pattern. - Oder anders ausgedrückt: Gibt es einen Algorithmus / eine Strategie, um die Erzeugung einer Produktfamilie zu steuern, dann kommt das Factory Method Pattern in Betracht. Dieses lässt sich gut mit dem Template Pattern, oder auch Strategy Pattern kombinieren, da man mit einer Schablone (Template) die Schritte zum Erstellen des untergeordneten Elements abstrahieren kann.
Die Anregungen zum konzeptionellen Beispiel finden Sie unter
https://refactoring.guru/design-patterns
und
vor.
