Menu
Coddy logo textTech

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.

challenge icon

Aufgabe

Einfach

Erstellen 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 ein PetType-enum mit den Werten PET_DOG, PET_CAT und PET_BIRD. Erstelle eine Basis-Pet-Struktur, die einen Funktionszeiger für speak enthält (der einen const Pet* entgegennimmt und nichts zurückgibt). Deklariere die Factory-Funktion create_pet, die einen PetType entgegennimmt und einen Pet* zurückgibt, sowie eine free_pet-Funktion zur Speicherfreigabe.
  • pet.c: Definiere drei konkrete Haustierstrukturen, Dog, Cat und Bird, die jeweils Pet als erstes Member enthalten. Implementiere für jeden Typ eine speak-Funktion:
    • Hunde geben aus: Woof!
    • Katzen geben aus: Meow!
    • Vögel geben aus: Tweet!
    Erstelle Konstruktorfunktionen für jeden Haustiertyp, die Speicher reservieren und die passende speak-Funktion verknüpfen. Implementiere anschließend die create_pet-Factory: Verwende eine switch-Anweisung für den PetType, um den passenden Konstruktor aufzurufen und das Ergebnis als Pet* zurückzugeben. Gib bei ungültigen Typen NULL zurück. Implementiere free_pet, um den reservierten Speicher freizugeben.
  • 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 seine speak-Funktion polymorph über den Basiszeiger Pet* 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;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C-Compiler