Die abstrakte Fabrik (englischabstract factory, kit) ist ein Entwurfsmuster aus dem Bereich der Softwareentwicklung, das zur Kategorie der Erzeugungsmuster (englisch creational patterns) gehört. Es definiert eine Schnittstelle zur Erzeugung einer Familie von Objekten, wobei die konkreten Klassen der zu instanziierenden Objekte nicht näher festgelegt werden.[1] Das Muster ist eines der Entwurfsmuster, die von der sogenannten Viererbande (GoF) publiziert wurden.
Eine abstrakte Fabrik vereinigt die Verantwortlichkeiten „Zusammenfassung der Objektgenerierung an einer Stelle“ und „Möglichkeit zu abstrakten Konstruktoren“ (siehe auch unten unter „Verwandte Entwurfsmuster“).
Akteure
AbstrakteFabrik
definiert eine Schnittstelle zur Erzeugung abstrakter Produkte einer Produktfamilie
KonkreteFabrik
erzeugt konkrete Produkte einer Produktfamilie durch Implementierung der Schnittstelle
AbstraktesProdukt
definiert eine Schnittstelle für eine Produktart
KonkretesProdukt
definiert ein konkretes Produkt einer Produktart durch Implementierung der Schnittstelle, wird durch die korrespondierende konkrete Fabrik erzeugt
Klient
verwendet die Schnittstellen der abstrakten Fabrik und der abstrakten Produkte
Der Austausch von Produktfamilien ist auf einfache Art und Weise möglich.
Nachteile
Neue Produktarten lassen sich schwer hinzufügen, da in allen konkreten Fabriken Änderungen vorzunehmen sind.
Verwendung in der Analyse
Wegen der gemeinsamen Komplexität der beiden wesentlichen Verantwortungen („Zusammenfassung der Objektgenerierung an einer Stelle“ und „Möglichkeit zu abstrakten Konstruktoren“) ist dieses Entwurfsmuster für die Analyse praktisch irrelevant.
Beispiele
C++
Diese C++11 Implementierung basiert auf dem vor C++98 Beispielcode im Buch Entwurfsmuster.
#include<iostream>enumRichtung{Norden,Sueden,Osten,Westen};classKartenEintrag{public:virtualvoidbetrete()=0;virtual~KartenEintrag()=default;};classRaum:publicKartenEintrag{public:Raum():raumNr(0){}Raum(intn):raumNr(n){}voidsetSeite(Richtungd,KartenEintrag*ms){std::cout<<"Raum::setSeite "<<d<<' '<<ms<<'\n';}virtualvoidbetrete(){}Raum(constRaum&)=delete;// DreierregelRaum&operator=(constRaum&)=delete;private:intraumNr;};classWand:publicKartenEintrag{public:Wand(){}virtualvoidbetrete(){}};classTuer:publicKartenEintrag{public:Tuer(Raum*r1=nullptr,Raum*r2=nullptr):raum1(r1),raum2(r2){}virtualvoidbetrete(){}Tuer(constTuer&)=delete;// DreierregelTuer&operator=(constTuer&)=delete;private:Raum*raum1;Raum*raum2;};classLabyrinth{public:voidfuegeRaumHinzu(Raum*r){std::cout<<"Labyrinth::fuegeRaumHinzu "<<r<<'\n';}Raum*raumNr(int)const{returnnullptr;}};classLabyrinthFabrik{public:LabyrinthFabrik()=default;virtual~LabyrinthFabrik()=default;virtualLabyrinth*erzeugeLabyrinth()const{returnnewLabyrinth;}virtualWand*erzeugeWand()const{returnnewWand;}virtualRaum*erzeugeRaum(intn)const{returnnewRaum(n);}virtualTuer*erzeugeTuer(Raum*r1,Raum*r2)const{returnnewTuer(r1,r2);}};// Wenn baueLabyrinth ein Objekt als Parameter erhält, das zum Erzeugen von Räumen, Wänden und Türen verwendet wird, dann können Sie die Klassen von Räumen, Wänden und Türen durch das Hereinreichen verschiedener Parameter verändern. Dies ist ein Beispiel für das Abstrakte-Fabrik-Muster (107).classLabyrinthSpiel{public:Labyrinth*baueLabyrinth(LabyrinthFabrik&fabrik){Labyrinth*einLabyrinth=fabrik.erzeugeLabyrinth();Raum*r1=fabrik.erzeugeRaum(1);Raum*r2=fabrik.erzeugeRaum(2);Tuer*eineTuer=fabrik.erzeugeTuer(r1,r2);einLabyrinth->fuegeRaumHinzu(r1);einLabyrinth->fuegeRaumHinzu(r2);r1->setSeite(Norden,fabrik.erzeugeWand());r1->setSeite(Osten,eineTuer);r1->setSeite(Sueden,fabrik.erzeugeWand());r1->setSeite(Westen,fabrik.erzeugeWand());r2->setSeite(Norden,fabrik.erzeugeWand());r2->setSeite(Osten,fabrik.erzeugeWand());r2->setSeite(Sueden,fabrik.erzeugeWand());r2->setSeite(Westen,eineTuer);returneinLabyrinth;}};intmain(){LabyrinthSpielspiel;LabyrinthFabrikfabrik;spiel.baueLabyrinth(fabrik);}
Es soll eine Spielesammlung per Software entwickelt werden. Die verwendeten Klassen sind dabei
Spielbrett (erstes abstraktes Produkt), auf das Spielfiguren platziert werden können und das beispielsweise eine Methode besitzt, um sich auf dem Bildschirm anzuzeigen. Konkrete, davon abgeleitete Produkte sind Schachbrett, Mühlebrett, Halmabrett etc.
Spielfigur (zweites abstraktes Produkt), die auf ein Spielbrett gesetzt werden kann. Konkrete, davon abgeleitete Produkte sind Hütchen, Schachfigur (der Einfachheit halber soll es hier nur einen Typ an Schachfiguren geben), Holzsteinchen etc.
Spielfabrik (abstrakte Fabrik), die Komponenten (Spielbrett, Spielfiguren) eines Gesellschaftsspiels erstellt. Konkrete, davon abgeleitete Fabriken sind beispielsweise Mühlefabrik, Damefabrik, Schachfabrik etc.
Ein Klient (z. B. eine Instanz einer Spieler- oder Spielleiter-Klasse) kann sich von der abstrakten Fabrik Spielfiguren bzw. ein Spielbrett erstellen lassen. Je nachdem, welches konkrete Spiel gespielt wird, liefert beispielsweise
die Schachfabrik ein Schachbrett und Schachfiguren,
die Damefabrik ebenfalls ein Schachbrett, aber Holzsteinchen,
die Mühlefabrik ein Mühlebrett, aber ebenfalls Holzsteinchen.
Die abstrakte Fabrik ist einfach eine mehrfache Anwendung der Fabrikmethode. Die abstrakte Fabrik kann daher eine ganze Produktfamilie austauschbar machen, während sich die Fabrikmethode nur auf ein Produkt bezieht.
Soll generell eine zusätzliche Hierarchie von Fabriken zu einer Hierarchie von Produkten vermieden werden, kann das Muster des Prototyps verwendet werden. Bei diesem Muster werden zur Erzeugung neuer Objekte prototypische Instanzen kopiert.