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é.
Défi
FacileConstruisons 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érationPetTypeavec les valeursPET_DOG,PET_CATetPET_BIRD. Créez une structure de basePetqui contient un pointeur de fonction pourspeak(qui prend unconst Pet*et ne renvoie rien). Déclarez la fonction d'usinecreate_petqui prend unPetTypeet renvoie unPet*, ainsi qu'une fonctionfree_petpour le nettoyage.pet.c: Définissez trois structures d'animaux concrètes —Dog,CatetBird— chacune intégrantPetcomme premier membre. Implémentez une fonction speak pour chaque type :- Les chiens affichent :
Woof! - Les chats affichent :
Meow! - Les oiseaux affichent :
Tweet!
create_pet— utilisez une instruction switch sur lePetTypepour appeler le bon constructeur et renvoyer le résultat sous forme dePet*. Pour les types invalides, renvoyezNULL. Implémentezfree_petpour libérer la mémoire allouée.- Les chiens affichent :
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 fonctionspeakde manière polymorphe via le pointeur de basePet*, 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;
}
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
1Bases de la programmation modulaire
Fichiers d'en-têteGardes d'inclusionFichiers sourcesFonctions statiquesRécapitulatif : Calculatrice modulaire4Encapsulation
Concept des pointeurs opaquesDéfinir des structures opaquesGetters et settersValidation dans les settersRécapitulatif : La boîte secrète2Objets et méthodes
Structs comme objetsLe pointeur 'Self'Rigueur du mot-clé constPointeur vs ValeurMéthodes utilitairesRécapitulatif : Point Manager5Projet : Compte bancaire simple
Configuration du projetImplémentation du compte8Polymorphisme
Pointeurs de fonctions dans les structuresSimulation de méthodesLe concept d'interfaceImplémentation d'interfacesItération polymorphiqueRécapitulatif : Greeter11Patrons de conception en C
Patron SingletonPatron FabriquePatron ItérateurRécapitulatif : Logger Factory3Cycle de vie des objets
Pattern de constructeurPattern de destructeurInitialisation sur la pileCopie profondeRécapitulatif : String Wrapper6Héritage par composition
Imbrication de structLa règle du premier membreAccès aux membres parentsUpcastingRécapitulatif : Hiérarchie des formes9Projet : Dessinateur de formes
Aperçu du projetImplémentation du cercle