Factory Pattern: Alle Informationen zum Factory Method Pattern

Mehr als 500.000 Exemplare sind von „Design Patterns: Elements of Reusable Object-Oriented Software“ seit der Veröffentlichung im Jahr 1994 verkauft worden. Das Buch für Software-Entwickler beschreibt 23 verschiedenartige Design Patterns, die in Fachkreisen auch als „Gang of Four“-Design-Patterns („Viererbande“-Entwurfsmuster) bekannt sind – eine Bezeichnung, die auf die vier Autoren Erich Gamma, John Vlissides, Ralph Johnson und Richard Helm zurückgeht.

Zu den zahlreichen Design-Strategien, die im Rahmen dieses Werks vermittelt werden, zählt auch die sogenannte Fabrikmethode (engl. factory method), die es einer Klasse ermöglicht, die Erzeugung von Objekten an Subklassen zu delegieren. Konkrete Informationen zur Nutzung dieser praktischen Methode liefert insbesondere das Factory Method Pattern, das heute häufig einfach als Factory Pattern bezeichnet wird.

Was ist das Factory Pattern (Factory Method Pattern)?

Das Factory Method Pattern beschreibt einen Programmieransatz, nach dem sich Objekte kreieren lassen, ohne die exakte Klasse dieser Objekte spezifizieren zu müssen. Dadurch lässt sich das erstellte Objekt flexibel und bequem austauschen. Für die Umsetzung greifen Entwickler dabei auf die namensgebende Factory Method zurück, zu Deutsch Fabrikmethode. Diese wird wahlweise in einer Schnittstelle spezifiziert und per Child-Klasse implementiert oder per Basisklasse implementiert und optional überschrieben (von abgeleiteten Klassen). Das Pattern bzw. die Methode rücken damit an die Stelle der regulären Klassen-Konstruktors, um die Erzeugung von Objekten von den Objekten selbst zu lösen und so ein Befolgen der SOLID-Prinzipien zu ermöglichen.

Hinweis

Die SOLID-Prinzipien sind eine Teilgruppe der Prinzipien objektorientierten Designs, die den Entwicklungsprozess objektorientierter Software verbessern sollen. Das Akronym „SOLID“ steht dabei für folgende fünf Prinzipien:

  • Single-Responsibility-Prinzip: Jede Klasse soll nur eine einzige Verantwortung besitzen.
  • Open-Closed-Prinzip: Software-Einheiten sollen erweiterbar sein, ohne hierfür ihr Verhalten ändern zu müssen.
  • Liskovsches Substitutionsprinzip: Eine abgeleitete Klasse soll stets anstelle ihrer Basisklasse einsetzbar sein.
  • Interface-Segregation-Prinzip: Interfaces sollen perfekt auf die Anforderungen der zugreifenden Clients abgestimmt sein.
  • Dependency-Inversion-Prinzip: Klassen auf einem höheren Abstraktionslevel sollen niemals von Klassen eines niedrigeren Abstraktionslevels abhängig sein.

Anstelle der üblichen Bezeichnung nutzt man heute in vielen Fällen den verkürzten Begriff Factory Pattern (dt. Factory-Muster) bzw. Factory Design Pattern (dt. Factory-Entwurfsmuste), wobei dieser im GoF-Werk nicht zu finden ist. Bei einem Blick in das Buch finden Sie neben dem hier thematisierten Factory Method Pattern lediglich das ähnliche Abstract Factory Pattern, das eine Schnittstelle zur Kreation einer Familie von Objekten definiert, deren konkrete Klassen erst während der Laufzeit festgelegt werden.

Welches Ziel verfolgt das Factory Design Pattern?

Das Factory Pattern will ein grundlegendes Problem bei der Instanziierung – also der Kreation eines konkreten Objekts einer Klasse – in der objektorientierten Programmierung lösen: Ein Objekt direkt innerhalb der Klasse zu erstellen, die dieses Objekt benötigt bzw. verwenden soll, ist prinzipiell möglich, aber sehr unflexibel. Es bindet die Klasse an dieses bestimmte Objekt und macht es unmöglich, die Instanziierung unabhängig von der Klasse zu verändern. Derartiger Code wird durch den Factory-Pattern-Ansatz vermieden, indem hier zunächst eine separate Operation für das Erstellen des Objekts definiert wird – die Factory-Methode. Sobald diese aufgerufen wird, generiert sie das Objekt, anstelle des bereits erwähnten Klassen-Konstruktors.

Zur Anzeige dieses Videos sind Cookies von Drittanbietern erforderlich. Ihre Cookie-Einstellungen können Sie hier aufrufen und ändern.

Factory Pattern: UML-Diagramm des Factory-Entwurfsmusters

In Software, die sich an dem Factory Design Pattern orientiert, wird der Code eines zu erstellenden Objekts (in diesem Zusammenhang auch als „Produkt“ bezeichnet) also separat in eine eigene Klasse ausgelagert. Diese abstrakte Klasse, auch „Creator“ oder – passend zum Pattern – „Factory“ (dt. Fabrik) genannt, delegiert die Objektinstanziierung ihrerseits an eine Unterklasse (ConcreteCreator), die letztlich darüber entscheidet, welches Produkt erstellt wird. Hierfür übernimmt der ConcreteCreator die Methode createProduct() und gibt anschließend ein ConcreteProdukt zurück, das optional vom Creator mit Herstellungscode erweitert werden kann, bevor es als fertiges Produkt an die Schnittstelle übergeben wird.

Deutlicher wird der Prozess im nachfolgenden UML-Klassendiagramm des Factory Patterns, das die geschilderten Zusammenhänge und Vorgänge grafisch zusammenfasst.

Die Vor- und Nachteile des Factory Design Patterns

Der Aufruf einer Programmmethode wird beim Factory Pattern gänzlich von der Implementierung neuer Klassen separiert, was einige Vorzüge mit sich bringt. So wirkt sich dieser Umstand insbesondere auf die Erweiterbarkeit einer Software aus: Factory-Instanzen besitzen ein hohes Maß an Eigenständigkeit und erlauben das Hinzufügen neuer Klassen, ohne dass sich die Applikation hierfür in irgendeiner Weise ändern muss – parallel zur Laufzeit. Es genügt, die Factory-Schnittstelle zu implementieren und den Creator entsprechend zu instanziieren (via ConcreteCreator).

Ein weiterer Vorteil besteht in der guten Testbarkeit der Factory-Komponenten. Implementiert ein Creator beispielsweise drei Klassen, so lässt sich deren Funktionalität einzeln und unabhängig von der aufrufenden Klasse testen. Bei letzterer ist lediglich sicherzustellen, dass sie den Creator ordnungsgemäß aufruft, selbst wenn die Software an dieser Stelle zu einem späteren Zeitpunkt erweitert wird. Ebenfalls vorteilhaft ist die Möglichkeit, Fabrikmethoden (anders als bei einem Klassen-Konstruktor) mit einem aussagekräftigen Namen versehen zu können.

Die große Schwäche des Factory Design Patterns ist die Tatsache, dass seine Umsetzung zu einem starken Anstieg der eingebundenen Klassen führt, denn jedes ConcreteProdukt erfordert immer auch einen ConcreteCreator. So gewinnbringend der Factory-Ansatz hinsichtlich der Erweiterung einer Software grundsätzlich ist, so nachteilhaft ist er außerdem, wenn es um den aufzubringenden Aufwand geht: Soll eine Produktfamilie ergänzt werden, müssen nicht nur die Schnittstelle, sondern auch alle untergeordneten ConcreteCreator-Klassen entsprechend angepasst werden. Eine gute Vorausplanung hinsichtlich der benötigten Produkttypen ist folglich unverzichtbar.

Vorteile Nachteile
Modulare Erweiterbarkeit der Applikation Hohe Zahl an erforderlichen Klassen
Gute Testbarkeit Erweiterung der Applikation ist sehr aufwendig
Aussagekräftige Methoden-Namen  

Wo wird das Factory Method Pattern eingesetzt?

Das Factory Pattern kann sich in verschiedenen Anwendungsszenarien als wertvoll erweisen. Insbesondere Software, bei der die konkret zu erstellenden Produkte nicht bekannt sind bzw. nicht im Vorhinein definiert werden, profitiert von dem alternativen Ansatz für das Subklassen-Management. Typische Anwendungsfälle sind daher Frameworks oder Klassenbibliotheken, die als Grundgerüst für die Entwicklung moderner Applikationen quasi unverzichtbar geworden sind.

Auch Authentifizierungssysteme profitieren von den Vorzügen des Factory Design Patterns: Anstelle einer zentralen Klasse mit diversen Parametern, die je nach Nutzerberechtigung variieren, lässt sich hier der Authentifizierungsprozess an Factory-Klassen delegieren, die eigenständig Entscheidungen über das Handling des jeweiligen Users treffen.

Zudem eignet sich das Design nach dem Factory-Pattern-Ansatz generell natürlich für sämtliche Software, in der planmäßig und in aller Regelmäßigkeit neue Klassen hinzugefügt werden – insbesondere, wenn diese Klassen den gleichen Erstellungsprozess durchlaufen müssen.

Factory Pattern: Beispiel (PHP)

Das Factory-Entwurfsmuster kann in Applikationen verschiedenster Programmiersprachen zum Einsatz kommen. Zu den bekanntesten Vertretern zählen dabei Java, JavaScript, C++, C#, Python und PHP. Letztgenannte Skriptsprache kommt auch im nachfolgenden Praxisbeispiel, bei dem wir uns an folgendem Artikel im Blog Phpmonkeys orientieren, zum Einsatz.

Gesetzt ist in diesem Fall ein Szenario mit der abstrakten Klasse „Car“ (Creator) und der Factory-Klasse „CarFactory“ (ConcreteCreator). Erstere ist möglichst simpel gestaltet und enthält lediglich Code, um eine Farbe für das Auto zu setzen – Standardfarbe: weiß – und diese auszulesen:

class Car {
	private $color = null;
	public function __construct() {
		$this->color = "white";
	}
	public function setColor($color) {
		$this->color = $color;
	}
	public function getColor() {
		return $this->color;
	}
}

In der Factory-Klasse werden zudem Methoden für „rote“ (red) und „blaue“ (blue) Autos sowie eine private Methode für die eigentliche Klassenerstellung eingeführt:

class CarFactory {
	private function __construct() {
	}
	public static function getBlueCar() {
		return self::getCar("blue");
	}
	public static function getRedCar() {
		return self::getCar("red");
	}
	private static function getCar($color) {
		$car = new Car();
		$car->setColor($color);
		return $car;
	}
}

Wahlweise lässt sich diese noch sehr übersichtliche Factory-Klasse nun – dank dem Factory Method Pattern bzw. der Fabrikmethode – noch mit den verschiedensten weiteren Automerkmalen wie weiteren Farben, der Automarke oder dem Preis erweitern.