Factory-Muster
Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 55 von 61.
Das Factory-Muster zentralisiert die Objekterstellung in einer einzigen Funktion. Anstatt malloc- und Initialisierungscode im gesamten Programm zu verteilen, rufst du eine Funktion auf, die entscheidet, was erstellt werden soll, und ein sofort einsatzbereites Objekt zurückgibt.
Dieses Muster ist besonders leistungsfähig in Kombination mit Polymorphie. Eine Factory kann über einen gemeinsamen Basispointer verschiedene konkrete Typen zurückgeben und dabei die Erstellungsdetails vor dem Aufrufer verbergen. Der Aufrufer bittet einfach um „eine Form“, und die Factory entscheidet, ob sie einen Kreis, ein Rechteck oder etwas anderes erstellt.
Hier ist eine typische Factory-Implementierung:
typedef enum {
SHAPE_CIRCLE,
SHAPE_RECTANGLE
} ShapeType;
Shape* create_shape(ShapeType type) {
switch (type) {
case SHAPE_CIRCLE:
return (Shape*)create_circle(5.0);
case SHAPE_RECTANGLE:
return (Shape*)create_rectangle(4.0, 3.0);
default:
return NULL;
}
}Die Factory nimmt einen Bezeichner (normalerweise ein Enum) entgegen und verwendet eine switch-Anweisung, um zu bestimmen, welcher Konstruktor aufgerufen werden soll. Sie gibt unabhängig vom tatsächlich erstellten Typ einen Shape* zurück. Der Aufrufer muss weder Circle noch Rectangle kennen. Er arbeitet einfach mit dem Basistyp:
Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s); // polymorpher Aufruf
free_shape(s);Dieses Muster macht das Hinzufügen neuer Typen einfach: Füge einfach einen neuen Enum-Wert und einen neuen Fall in der Factory hinzu. Der Rest deines Codes bleibt unverändert.
Aufgabe
EinfachErstellen wir eine Haustierfabrik: ein System, das verschiedene Haustiertypen über eine einzige Factory-Funktion erstellt. Anstatt die Erstellungslogik über deinen gesamten Code zu verteilen, zentralisierst du sie an einer Stelle, die anhand eines Eingabe-Identifiers entscheidet, welche Art von Haustier erstellt werden soll.
Du organisierst deinen Code über drei Dateien:
pet.h: Definiere einPetType-enum mit den WertenPET_DOG,PET_CATundPET_BIRD. Erstelle eine Basis-Pet-Struktur, die einen Funktionszeiger fürspeakenthält (der einenconst Pet*entgegennimmt und nichts zurückgibt). Deklariere die Factory-Funktioncreate_pet, die einenPetTypeentgegennimmt und einenPet*zurückgibt, sowie einefree_pet-Funktion zur Speicherfreigabe.pet.c: Definiere drei konkrete Haustierstrukturen,Dog,CatundBird, die jeweilsPetals erstes Member enthalten. Implementiere für jeden Typ eine speak-Funktion:- Hunde geben aus:
Woof! - Katzen geben aus:
Meow! - Vögel geben aus:
Tweet!
create_pet-Factory: Verwende eine switch-Anweisung für denPetType, um den passenden Konstruktor aufzurufen und das Ergebnis alsPet*zurückzugeben. Gib bei ungültigen TypenNULLzurück. Implementierefree_pet, um den reservierten Speicher freizugeben.- Hunde geben aus:
main.c: Lies eine Ganzzahl ein, die den Haustiertyp darstellt (0 für Hund, 1 für Katze, 2 für Vogel). Verwende deine Factory, um das passende Haustier zu erstellen, rufe seinespeak-Funktion polymorph über den BasiszeigerPet*auf und gib anschließend das Haustier frei.
Dein Programm erhält eine Eingabe: eine Ganzzahl, die angibt, welches Haustier erstellt werden soll.
Beispielausgabe, wenn die Eingabe 0 ist:
Woof!Beispielausgabe, wenn die Eingabe 1 ist:
Meow!Beispielausgabe, wenn die Eingabe 2 ist:
Tweet!Das Schöne am Factory Pattern ist, dass main.c nichts über die Strukturen Dog, Cat oder Bird wissen muss. Es arbeitet nur mit dem Basistyp Pet. Wenn du später einen neuen Haustiertyp hinzufügst, musst du lediglich einen neuen enum-Wert und einen neuen case in der Factory ergänzen, ohne Code zu ändern, der Haustiere verwendet.
Probier es selbst
#include <stdio.h>
#include "pet.h"
int main(void) {
int type;
scanf("%d", &type);
// TODO: Verwende die Factory, um das passende Pet zu erstellen
// Hinweis: Cast den int zu PetType
// TODO: Rufe die speak-Funktion polymorph über den Pet*-Zeiger auf
// TODO: Gib das Pet frei
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der modularen Programmierung
Header-DateienInclude GuardsQuelldateienStatische FunktionenWiederholung: Modularer Taschenrechner4Kapselung
Konzept der Opaque PointersOpaque Structs definierenGetter und SetterValidierung in SetternRückblick: Die geheime Box2Objekte und Methoden
Structs als ObjekteDer 'Self'-PointerConst-CorrectnessPointer vs. WertHilfsmethodenZusammenfassung: Point Manager5Projekt: Einfaches Bankkonto
Projekt-SetupImplementierung des Kontos3Objekt-Lebenszyklus
Konstruktor-MusterDestruktor-MusterStack-InitialisierungTiefe KopieRückblick: String-Wrapper6Vererbung durch Komposition
Struct-EinbettungDie First-Member-RegelZugriff auf Parent-MemberUpcastingRückblick: Formenhierarchie9Projekt: Formen-Zeichner
ProjektübersichtKreis-ImplementierungRechteck-ImplementierungPolymorphe VerwendungShape-ContainerÜbe selbstständig: Online-C-Compiler