abstrakte Fabrik vs. Fabrik (Entwurfsmuster)
-
Kann mir jemand mit einfachen Worten den Unterschied erklären und wann man was verwenden sollte?
-
Reicht dir die Erklärung in der Wikipedia?
-
Jain, ich würd gerne mal was von Leuten hören, die damit schon Erfahrung haben, und das mal in einfachen Worten wiedergeben können...
-
Um das mal zu konkretisieren:
Ich habe Klasse B und C, welche beide von der abstrakten Klasse A abgeleitet sind. Eine Fabrik soll mir nun Bs und Cs erzeugen. Welche Fabrik brauche ich dafür (abstrakte oder konkrete)?
-
Du müsstest das noch ein bisschen weiter konkretisieren. Wovon hängt denn ab, ob B oder C erzeugt werden sollen?
Abtrakte Fabriken brauchst du, wenn du verschiedene Konfigurationen hast, so dass in der einen Konfiguration nur B-Objekte und in der anderen nur C-Objekte erzeugt werden sollen.
Das klingt jetzt nicht besonders sinnig, aber du hast mit A, B, C angefangen
Hast du dagegen eher das Bedürfnis, Methoden wie A* createB() und A* createC() aufzurufen, dann brauchst du keine abstrakte Fabrik.
-
Wenn ich mir so die Anleitung zur (normalen) Fabrik anschaue, versteh ich das so: Man macht eine abstrakte Klasse, die Fabrik, und leitet davon Fabriken für Produkt B und C ab. Ich muss also für jedes Produkt eine eigene Unterklasse erstellen!!
Aber kann ich nicht einfach EINE Fabrik erstellen, dessen Produkte ich dann caste??
-
Die abstrakte Fabrik definiert die Schnittstelle, welche Produkte von konkreten Fabriken erzeugt werden können. Ebenso definiert das abstrakte Produkt lediglich die Schnittstelle zu konkreten Produkten. Die konkrete Fabrik erzeugt die konkreten Produkte.
Die Verwendung einer abstrakten Fabrik dient der Austauschbarkeit von konkreten Fabriken ohne Änderungen am Klientencode vornehmen zu müssen, da dieser die Schnittstelle der abstrakten Fabrik verwendet. Selbiges gilt auch für die abstrakten und konkreten Produkte. Den Klient interessiert dabei nicht, welche konkreten Fabriken/Produkte verwendet werden, noch weniger möchte er irgendetwas in seinem Code casten. Von einem Kunden deiner Klassenbibliothken wirst Du sicherlich pure Begeisterung vernehmen, wenn dem Klassenupdate noch ein kleiner roter Zettel beiliegt auf dem steht, dass er nach dem Update bitteschön noch ein paar Casts in seinem Code durchzuführen hat, damit er auch von dem Update vollends profitiert...
Die Schwierigkeit an der ganzen Sache ist, eine Schnittstelle zu finden, die den Klienten bis in alle Zeiten glücklich macht.
-
Ich habe jetzt mal ein Beispiel:
class Product { protected: int Number; public: virtual int getNumber() = 0; virtual void setNumber(int intNumber) = 0; };
class ProductA: public Product { protected: int NumberA; public: virtual int getNumber() { return Number; } virtual void setNumber(int intNumber) { Number = intNumber; } virtual int getNumberA() { return NumberA; } virtual void setNumberA(int intNumberA) { NumberA = intNumberA; } };
class Factory { public: virtual Product* create() = 0; };
class FactoryConcrete: public Factory { public: virtual Product* create() { return new ProductA(); } };
int main() { FactoryConcrete objFactory; Product* objProduct= objFactory.create(); objProduct->setNumberA(4); // <-- Fehler!
Es kommt zum Fehler, da ProductA weitere Methoden enthält, die die Basisklasse Product nicht bietet.
Ich möchte aber trotzdem ProductA erstellen! Wie muss ich vorgehen?
-
Wie muss ich vorgehen?
der factory eine methode createProductA spendieren. aber vorher nochmal das factory entwurfsmuster und das konzept der polymorphie genau angucken und verstehen
-
hmm, wo ist der fehler??
-
#include <string> #include <iostream> using namespace std; class AbstraktesProduktA { public: virtual ~AbstraktesProduktA() {} virtual std::string WasBinIch() = 0; }; class AbstraktesProduktB { public: virtual ~AbstraktesProduktB() {} virtual std::string WasBinIch() = 0; }; class KonkretesProduktA1 : public AbstraktesProduktA { public: virtual ~KonkretesProduktA1() {} std::string WasBinIch() { return "KonkretesProduktA in Fabrik1 hergestellt!"; } }; class KonkretesProduktB1 : public AbstraktesProduktB { public: ~KonkretesProduktB1() {} std::string WasBinIch() { return "KonkretesProduktB in Fabrik1 hergestellt!"; } }; class KonkretesProduktA2 : public AbstraktesProduktA { public: virtual ~KonkretesProduktA2() {} std::string WasBinIch() { return "KonkretesProduktA in Fabrik2 hergestellt!"; } }; class KonkretesProduktB2 : public AbstraktesProduktB { public: ~KonkretesProduktB2() {} std::string WasBinIch() { return "KonkretesProduktB in Fabrik2 hergestellt!"; } }; class AbstrakteFabrik { public: virtual AbstraktesProduktA* ErzeugeProduktA() = 0; virtual AbstraktesProduktB* ErzeugeProduktB() = 0; }; class KonkreteFabrik1 : public AbstrakteFabrik { public: KonkretesProduktA1* ErzeugeProduktA() { return new KonkretesProduktA1; } KonkretesProduktB1* ErzeugeProduktB() { return new KonkretesProduktB1; } }; class KonkreteFabrik2 : public AbstrakteFabrik { public: KonkretesProduktA2* ErzeugeProduktA() { return new KonkretesProduktA2; } KonkretesProduktB2* ErzeugeProduktB() { return new KonkretesProduktB2; } }; int main() { // ich bin der client AbstrakteFabrik* Fab = new KonkreteFabrik1; AbstraktesProduktA* pA1 = Fab->ErzeugeProduktA(); AbstraktesProduktB* pB1 = Fab->ErzeugeProduktB(); delete Fab; Fab = new KonkreteFabrik2; AbstraktesProduktA* pA2 = Fab->ErzeugeProduktA(); AbstraktesProduktB* pB2 = Fab->ErzeugeProduktB(); cout << pA1->WasBinIch() << endl; cout << pA2->WasBinIch() << endl; cout << pB1->WasBinIch() << endl; cout << pB2->WasBinIch() << endl; // delete all return 0; }
Wird es hiermit klarer?
-
dieses posting geht nicht durch den spamfilter. falls doch: sorry. http://www.cefe.de/ergebnisse/klassische-fehler.html
-
Ich habe eine Frage dazu, da ich nicht weiß wie dies hinzubekommen ist.
Ich möchte (so denke ich) eine Abstrakte Fabrik haben, die mir Fabriken für ein Interface bereitstellt. Der Client holt sich dann eine Fabrik und erzeugt darauf mittels eines Parameters Objekte die dieses Interface erfüllen. Nur woher weiß die abstrakte Fabrik von den konkreten Unterfabriken? Man könnte dies darin irgendwie codieren, aber dazu muß man ja wieder die jeweiligen Instanzen kenne und schafft sich Abhängigkeiten.
Ich habe mal irgendeine Template Implementation davon gesehen, die ich damals nicht verstanden habe und jetzt auch nicht wiederfinde. Dort wurden sozusagen neue Fabriktypen wie Plugins implementiert, die sich dann bei der abstrakten Fabrik registriert haben und die abstrake Fabrik konnte abhängig von ihren Parametern die konkreten Fabriken zur Objekterzeugung der Schnittstellenobjekte bauen ohne sie eigentlich selber zu kennen.
also:
abstractObject* AbstractFactory::baueMir("foo")
irgendwo wurde dann ein Typ registriert und bei "foo" wird diese Implementation genommen. Die AbstrakeFabrik weiß davon aber nix.
Weiß jemand wie das gehen kann? danke