Dieabstrakte Fabrik (englischabstract factory,kit) ist einEntwurfsmuster aus dem Bereich derSoftwareentwicklung, das zur Kategorie derErzeugungsmuster (englischcreational 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 sogenanntenViererbande (GoF) publiziert wurden.
Die abstrakte Fabrik wird angewendet, wenn
Eine typische Anwendung ist die Erstellung einergrafischen Benutzeroberfläche mit unterschiedlichenOberflächenmotiven.
Eine abstrakte Fabrik vereinigt die Verantwortlichkeiten „Zusammenfassung der Objektgenerierung an einer Stelle“ und „Möglichkeit zu abstrakten Konstruktoren“ (siehe auch unten unter „Verwandte Entwurfsmuster“).
AbstrakteFabrik
KonkreteFabrik
AbstraktesProdukt
KonkretesProdukt
Klient
Neue Produktarten lassen sich schwer hinzufügen, da in allen konkreten Fabriken Änderungen vorzunehmen sind.
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.
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);}
Die Programmausgabe ist ähnlich zu:
Labyrinth::fuegeRaumHinzu0x18aeed0Labyrinth::fuegeRaumHinzu0x18aeef0Raum::setSeite00x18af340Raum::setSeite20x18aef10Raum::setSeite10x18af360Raum::setSeite30x18af380Raum::setSeite00x18af3a0Raum::setSeite20x18af3c0Raum::setSeite10x18af3e0Raum::setSeite30x18aef10
Es soll eine Spielesammlung per Software entwickelt werden. Die verwendeten Klassen sind dabei
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
<?php// abstraktes Produkt AabstractclassSpielbrett{abstractfunctionaufstellen();}// abstraktes Produkt BabstractclassSpielfigur{abstractfunctionbewegen();}// abstrakte FabrikabstractclassSpielfabrik{abstractfunctionSpielbrettErzeugen();abstractfunctionSpielfigurErzeugen();}// konkrete Fabrik 1classDameextendsSpielfabrik{publicfunctionSpielbrettErzeugen(){returnnewSchachbrett();}publicfunctionSpielfigurErzeugen(){returnnewDamestein();}}// konkrete Fabrik 2classSchachextendsSpielfabrik{publicfunctionSpielbrettErzeugen(){returnnewSchachbrett();}publicfunctionSpielfigurErzeugen(){returnnewSchachfigur();}}// konkrete Fabrik 3classMuehleextendsSpielfabrik{publicfunctionSpielbrettErzeugen(){returnnewMuehlebrett();}publicfunctionSpielfigurErzeugen(){returnnewDamestein();}}classSchachbrettextendsSpielbrett{publicfunctionaufstellen(){echo"Schachbrett aufgestellt.".PHP_EOL;}}classMuehlebrettextendsSpielbrett{publicfunctionaufstellen(){echo"Mühle-Brett aufgestellt.".PHP_EOL;}}classDamesteinextendsSpielfigur{publicfunctionbewegen(){echo"Damestein bewegt.".PHP_EOL;}}classSchachfigurextendsSpielfigur{publicfunctionbewegen(){echo"Schachfigur bewegt.".PHP_EOL;}}functiontesteSpiel(Spielfabrik$fabrik){$brett=$fabrik->SpielbrettErzeugen();$figur=$fabrik->SpielfigurErzeugen();$brett->aufstellen();$figur->bewegen();}testeSpiel(newDame());testeSpiel(newMuehle());testeSpiel(newSchach());
Ausgabe:
Schachbrett aufgestellt.Damestein bewegt.Mühle-Brett aufgestellt.Damestein bewegt.Schachbrett aufgestellt.Schachfigur bewegt.
Die abstrakte Fabrik ist einfach eine mehrfache Anwendung derFabrikmethode. 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 desPrototyps verwendet werden. Bei diesem Muster werden zur Erzeugung neuer Objekte prototypische Instanzen kopiert.