Menu
Coddy logo textTech

Patron Fabrique

Fait partie de la section Object Oriented Programming du Journey C de Coddy — leçon 55 sur 61.

Le patron Factory centralise la création d'objets dans une seule fonction. Au lieu de disperser malloc et le code d'initialisation à travers votre programme, vous appelez une seule fonction qui décide quoi créer et renvoie un objet prêt à l'emploi.

Ce patron est particulièrement puissant lorsqu'il est combiné avec le polymorphisme. Une fabrique peut retourner différents types concrets via un pointeur de base commun, masquant les détails de création pour l'appelant. L'appelant demande simplement « une forme » et la fabrique décide s'il faut construire un cercle, un rectangle ou autre chose.

Voici une implémentation typique de fabrique :

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;
    }
}

La fabrique prend un identifiant (généralement une énumération) et utilise une instruction switch pour déterminer quel constructeur appeler. Elle retourne un Shape* quel que soit le type réel créé. L'appelant n'a pas besoin de connaître Circle ou Rectangle — il travaille simplement avec le type de base :

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // appel polymorphe
free_shape(s);

Ce patron facilite l'ajout de nouveaux types : il suffit d'ajouter une nouvelle valeur d'enum et un nouveau cas dans la factory. Le reste de votre code reste inchangé.

challenge icon

Défi

Facile

Construisons une Pet Factory (Usine d'animaux) — un système qui crée différents types d'animaux de compagnie via une seule fonction d'usine. Au lieu de disperser la logique de création dans tout votre code, vous la centraliserez en un seul endroit qui décide quel type d'animal créer en fonction d'un identifiant d'entrée.

Vous organiserez votre code sur trois fichiers :

  • pet.h : Définissez une énumération PetType avec les valeurs PET_DOG, PET_CAT et PET_BIRD. Créez une structure de base Pet qui contient un pointeur de fonction pour speak (qui prend un const Pet* et ne renvoie rien). Déclarez la fonction d'usine create_pet qui prend un PetType et renvoie un Pet*, ainsi qu'une fonction free_pet pour le nettoyage.
  • pet.c : Définissez trois structures d'animaux concrètes — Dog, Cat et Bird — chacune intégrant Pet comme premier membre. Implémentez une fonction speak pour chaque type :
    • Les chiens affichent : Woof!
    • Les chats affichent : Meow!
    • Les oiseaux affichent : Tweet!
    Créez des fonctions constructeurs pour chaque type d'animal qui allouent de la mémoire et configurent la fonction speak appropriée. Implémentez ensuite l'usine create_pet — utilisez une instruction switch sur le PetType pour appeler le bon constructeur et renvoyer le résultat sous forme de Pet*. Pour les types invalides, renvoyez NULL. Implémentez free_pet pour libérer la mémoire allouée.
  • main.c : Lisez un entier représentant le type d'animal (0 pour dog, 1 pour cat, 2 pour bird). Utilisez votre usine pour créer l'animal approprié, appelez sa fonction speak de manière polymorphe via le pointeur de base Pet*, puis libérez l'animal.

Votre programme recevra une entrée : un entier indiquant quel animal créer.

Exemple de sortie lorsque l'entrée est 0 :

Woof!

Exemple de sortie lorsque l'entrée est 1 :

Meow!

Exemple de sortie lorsque l'entrée est 2 :

Tweet!

La beauté du pattern Factory est que main.c n'a pas besoin de connaître les structures Dog, Cat ou Bird — il travaille uniquement avec le type de base Pet. Ajouter un nouveau type d'animal plus tard signifie simplement ajouter une nouvelle valeur d'énumération et un nouveau cas dans l'usine, sans modifier le code qui utilise les animaux.

Aide-mémoire

Le patron Factory centralise la création d'objets dans une seule fonction, masquant les détails de création à l'appelant.

Une fonction fabrique prend un identifiant (généralement une énumération) et utilise une instruction switch pour déterminer quel constructeur appeler, en retournant un pointeur de type de base :

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;
    }
}

L'appelant travaille uniquement avec le type de base, permettant un comportement polymorphe :

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // appel polymorphe
free_shape(s);

Avantages : L'ajout de nouveaux types nécessite seulement l'ajout d'une nouvelle valeur d'énumération et d'un cas switch, sans modifier le code existant qui utilise la fabrique.

Essayez vous-même

#include <stdio.h>
#include "pet.h"

int main(void) {
    int type;
    scanf("%d", &type);
    
    // TODO: Utiliser la factory pour créer l'animal de compagnie approprié
    // Hint: Caster l'int en PetType
    
    // TODO: Appeler la fonction speak de manière polymorphique via le pointeur Pet*
    
    // TODO: Libérer l'animal de compagnie
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Object Oriented Programming