Zum Inhalt springen

Abstrakte Fabrik

aus Wikipedia, der freien Enzyklopädie
Dies ist die aktuelle Version dieser Seite, zuletzt bearbeitet am 9. Mai 2023 um 11:11 Uhr durch imported>AndreAdrian (Beispiele: Überschrift C++ dazu).
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Die abstrakte Fabrik ({{Modul:Vorlage:lang}} Modul:Vorlage:lang:103: attempt to index field 'wikibase' (a nil value), {{Modul:Vorlage:lang}} Modul:Multilingual:153: attempt to index field 'data' (a nil value)) ist ein Entwurfsmuster aus dem Bereich der Softwareentwicklung, das zur Kategorie der Erzeugungsmuster (englisch {{Modul:Vorlage:lang}} Modul:Multilingual:153: attempt to index field 'data' (a nil value)) 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.<ref>Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: Entwurfsmuster. 5. Auflage. Addison-Wesley, 1996, ISBN 3-8273-1862-9, S. 107.</ref> Das Muster ist eines der Entwurfsmuster, die von der sogenannten Viererbande (GoF) publiziert wurden.

Verwendung

Die abstrakte Fabrik wird angewendet, wenn

  • ein System unabhängig von der Art der Erzeugung seiner Produkte arbeiten soll,
  • ein System mit einer oder mehreren Produktfamilien konfiguriert werden soll,
  • eine Gruppe von Produkten erzeugt und gemeinsam genutzt werden soll oder
  • wenn in einer Klassenbibliothek die Schnittstellen von Produkten ohne deren Implementierung bereitgestellt werden sollen.

Eine typische Anwendung ist die Erstellung einer grafischen Benutzeroberfläche mit unterschiedlichen Oberflä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“).

UML-Diagramm: Abstrakte Fabrik
UML-Diagramm: Abstrakte Fabrik

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

Vorteile

  • Der Klient ist von konkreten Klassen isoliert.<ref>Karl Eilebrecht, Gernot Starke: Patterns kompakt. Entwurfsmuster für effektive Software-Entwicklung. 3. Auflage. Spektrum Akademischer Verlag, 2010, ISBN 978-3-8274-2525-6, S. 26, doi:10.1007/978-3-8274-2526-3.</ref>
  • 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.

<syntaxhighlight lang="cpp">

  1. include <iostream>

enum Richtung {Norden, Sueden, Osten, Westen};

class KartenEintrag { public:

 virtual void betrete() = 0;
 virtual ~KartenEintrag() = default;

};

class Raum : public KartenEintrag { public:

 Raum() :raumNr(0) {}
 Raum(int n) :raumNr(n) {}
 void setSeite(Richtung d, KartenEintrag* ms) {
   std::cout << "Raum::setSeite " << d << ' ' << ms << '\n';
 }
 virtual void betrete() {}
 Raum(const Raum&) = delete; // Dreierregel
 Raum& operator=(const Raum&) = delete;

private:

 int raumNr;

};

class Wand : public KartenEintrag { public:

 Wand() {}
 virtual void betrete() {}

};

class Tuer : public KartenEintrag { public:

 Tuer(Raum* r1 = nullptr, Raum* r2 = nullptr)
   :raum1(r1), raum2(r2) {}
 virtual void betrete() {}
 Tuer(const Tuer&) = delete; // Dreierregel
 Tuer& operator=(const Tuer&) = delete;

private:

 Raum* raum1;
 Raum* raum2;

};

class Labyrinth { public:

 void fuegeRaumHinzu(Raum* r) {
   std::cout << "Labyrinth::fuegeRaumHinzu " << r << '\n';
 }
 Raum* raumNr(int) const {
   return nullptr;
 }

};

class LabyrinthFabrik { public:

 LabyrinthFabrik() = default;
 virtual ~LabyrinthFabrik() = default;
 virtual Labyrinth* erzeugeLabyrinth() const {
   return new Labyrinth;
 }
 virtual Wand* erzeugeWand() const {
   return new Wand;
 }
 virtual Raum* erzeugeRaum(int n) const {
   return new Raum(n);
 }
 virtual Tuer* erzeugeTuer(Raum* r1, Raum* r2) const {
   return new Tuer(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).

class LabyrinthSpiel { 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);
   return einLabyrinth;
 }

};

int main() {

 LabyrinthSpiel spiel;
 LabyrinthFabrik fabrik;
 spiel.baueLabyrinth(fabrik);

} </syntaxhighlight>

Die Programmausgabe ist ähnlich zu:

<syntaxhighlight lang="cpp"> Labyrinth::fuegeRaumHinzu 0x18aeed0 Labyrinth::fuegeRaumHinzu 0x18aeef0 Raum::setSeite 0 0x18af340 Raum::setSeite 2 0x18aef10 Raum::setSeite 1 0x18af360 Raum::setSeite 3 0x18af380 Raum::setSeite 0 0x18af3a0 Raum::setSeite 2 0x18af3c0 Raum::setSeite 1 0x18af3e0 Raum::setSeite 3 0x18aef10 </syntaxhighlight>

Es soll eine Spielesammlung per Software entwickelt werden. Die verwendeten Klassen sind dabei

  1. 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.
  2. 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.
  3. 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.

Programmierbeispiel in PHP

<syntaxhighlight lang="PHP"> <?php

   // abstraktes Produkt A
   abstract class Spielbrett {
       abstract function aufstellen();
   }
   // abstraktes Produkt B
   abstract class Spielfigur {
       abstract function bewegen();
   }
   // abstrakte Fabrik
   abstract class Spielfabrik {
       abstract function SpielbrettErzeugen();
       abstract function SpielfigurErzeugen();
   }
   // konkrete Fabrik 1
   class Dame extends Spielfabrik {
       public function SpielbrettErzeugen() {
           return new Schachbrett();
       }
       public function SpielfigurErzeugen() {
           return new Damestein();
       }
   }
   // konkrete Fabrik 2
   class Schach extends Spielfabrik {
       public function SpielbrettErzeugen() {
           return new Schachbrett();
       }
       public function SpielfigurErzeugen() {
           return new Schachfigur();
       }
   }
   // konkrete Fabrik 3
   class Muehle extends Spielfabrik {
       public function SpielbrettErzeugen() {
           return new Muehlebrett();
       }
       public function SpielfigurErzeugen() {
           return new Damestein();
       }
   }
   class Schachbrett extends Spielbrett {
       public function aufstellen() {
           echo "Schachbrett aufgestellt.".PHP_EOL;
       }
   }
   class Muehlebrett extends Spielbrett {
       public function aufstellen() {
           echo "Mühle-Brett aufgestellt.".PHP_EOL;
       }
   }
   class Damestein extends Spielfigur {
       public function bewegen() {
           echo "Damestein bewegt.".PHP_EOL;
       }
   }
   class Schachfigur extends Spielfigur {
       public function bewegen() {
           echo "Schachfigur bewegt.".PHP_EOL;
       }
   }
   function testeSpiel(Spielfabrik $fabrik) {
       $brett = $fabrik->SpielbrettErzeugen();
       $figur = $fabrik->SpielfigurErzeugen();
       $brett->aufstellen();
       $figur->bewegen();
   }
   

testeSpiel(new Dame()); testeSpiel(new Muehle()); testeSpiel(new Schach());

</syntaxhighlight> Ausgabe:

Schachbrett aufgestellt.
Damestein bewegt.
Mühle-Brett aufgestellt.
Damestein bewegt.
Schachbrett aufgestellt.
Schachfigur bewegt.

Verwandte Entwurfsmuster

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.

Weblinks

Commons: Abstrakte Fabrik – Album mit Bildern, Videos und Audiodateien

Einzelnachweise

<references />

<templatestyles src="Erweiterte Navigationsleiste/styles legacy.css" />Vorlage:Klappleiste/Anfang

Erzeugungsmuster

Abstrakte Fabrik | Erbauer | Fabrikmethode | Prototyp | Singleton | Multiton | Objektpool

Strukturmuster

Adapter | Brücke | Decorator | Fassade | Fliegengewicht | Kompositum | Stellvertreter

Verhaltensmuster

Beobachter | Besucher | Interpreter | Iterator | Kommando | Memento | Schablonenmethode | Strategie | Vermittler | Zustand | Zuständigkeitskette | Interceptor | Nullobjekt | Protokollstapel

Muster für objekt-
relationale Abbildung

Datentransferobjekt | Table Data Gateway | Row Data Gateway | Active Record | Unit of Work | Identity Map | Lazy Loading | Identity Field | Dependent Mapping | Embedded Value | Serialized LOB | Inheritance Mapper | Metadata Mapping | Query Object | Command-Query-Responsibility-Segregation

Nachrichten-
übermittlungsmuster
andere

Application Controller | Business Delegate | Data Access Object | Dependency Injection | Extension Interface | Fluent Interface | Inversion of Control (IoC) | Lock | Model View Controller (MVC) | Model View Presenter (MVP) | Model View Update (MVU) | Model View ViewModel (MVVM) | Page Controller | Registry | Remote Facade | Repository | Service Locator | Session State | Table Module | Template View | Threadpool | Transaction Script | Transform View | Two-Step View | Value Object

Vorlage:Klappleiste/Ende