Polar Code 🎭

Command Palette

Search for a command to run...

07
Pièce N°07

CHAPITRE 6 : FACTORY METHOD

La pièce était silencieuse, mais dans ma tête, les rouages tournaient. Le Singleton ? Un flic corrompu, utile dans l'urgence, mais qui pourrit le système. Maintenant, il fallait quelque chose de plus propre. Un moyen de déléguer la création sans tout contrôler, sans tout verrouiller. Un indicateur qui vous souffle quoi créer, mais laisse le comment à la discrétion des quartiers. C'est ça, la Factory Method. La délégation de pouvoir.

Déléguer la création

Le problème est simple, mais vicieux : une classe a besoin d'instancier un objet, mais elle ne sait pas exactement de quelle classe concrète il s'agit. Ou bien elle ne doit pas le savoir, pour rester flexible, découplée.

// Le problème : la classe de base dépend de classes concrètes.
class LogistiqueRoute {
    planifierLivraison() {
        const camion = new Camion(); // Création concrète, figée.
        camion.livrer();
    }
}

class LogistiqueMer {
    planifierLivraison() {
        const cargo = new Cargo(); // Une autre création concrète.
        cargo.livrer();
    }
}
// Duplication. Rigidité. Impossible de changer de type de transport
// sans modifier la logistique elle-même.

La Factory Method dit : « Ne crée pas toi-même. Demande à une méthode spécialisée de le faire pour toi. Et cette méthode, les sous-classes pourront la redéfinir. » La classe de base définit le processus (le squelette de l'algorithme), mais délègue l'étape cruciale de la création à ses sous-classes.

Classe abstraite vs implémentation

C'est le cœur du pattern. On travaille avec deux niveaux :

  1. Le Créateur (Creator) : Une classe (souvent abstraite) qui contient la logique métier principale et déclare la Factory Method (abstraite ou avec une implémentation par défaut).
  2. Les Créateurs Concrets (Concrete Creators) : Les sous-classes qui redéfinissent la Factory Method pour retourner une instance d'un Produit Concret spécifique.

Le Créateur ne dépend plus des classes concrètes de produits, mais seulement de l'interface ou classe abstraite du Produit.

Diagramme de classe

        +----------------------+        +-------------------+
        |      Creator         |        |    Product        |
        +----------------------+        +-------------------+
        |                      |        | + operation()     |
        +----------------------+        +-------------------+
        | + factoryMethod():   |                  ^
        |        Product       |                  |
        | + someOperation():   |                  |
        |        void          |         +-----------------+
        +----------------------+         |                 |
                    ^                    |                 |
                    |          +-----------------+ +-----------------+
         +-------------------+  | ConcreteProductA| | ConcreteProductB|
         | ConcreteCreatorA  |  +-----------------+ +-----------------+
         +-------------------+  | + operation()   | | + operation()   |
         | + factoryMethod(): | +-----------------+ +-----------------+
         |    Product {       |
         |      return new    |
         |    ConcreteProductA()|
         |    }               |
         +-------------------+

Cas d’usage

La Factory Method brille quand :

  • Une classe ne peut pas anticiper la classe des objets qu’elle doit créer.
  • Vous voulez que les sous-classes décident de l’objet à instancier (framework qui laisse les applications définir leurs propres composants).
  • Vous voulez localiser la logique d’instanciation pour éviter de la dupliquer à travers plusieurs classes similaires (comme nos Logistiques).
  • Le code doit travailler avec des familles d’objets liés, mais sans se soucier de leurs types concrets (précurseur de l'Abstract Factory).

Exemple conceptuel : Logistique de transport

Reprenons le problème initial avec l'élégance de la Factory Method.

// 1. Interface Produit (abstraction commune à tous les transports)
interface Transport {
    livrer(): string;
}

// 2. Produits Concrets
class Camion implements Transport {
    livrer(): string {
        return 'Livraison par la route dans un camion.';
    }
}

class Bateau implements Transport {
    livrer(): string {
        return 'Livraison par la mer dans un bateau.';
    }
}

// 3. Classe abstraite Créateur
abstract class Logistique {
    // LA FACTORY METHOD (abstraite). C'est le coeur du pattern.
    // Elle délègue la création d'un objet Transport aux sous-classes.
    public abstract creerTransport(): Transport;

    // Méthode de logistique principale (le "template").
    // Elle utilise la Factory Method, sans savoir quelle classe concrète est créée.
    public planifierLivraison(): string {
        // Appel à la factory method que les sous-classes vont implémenter.
        const transport = this.creerTransport();
        // Utilisation de l'objet produit, via son interface.
        return `Planification logistique : ${transport.livrer()}`;
    }
}

// 4. Créateurs Concrets
class LogistiqueRoute extends Logistique {
    // Implémentation de la Factory Method pour un produit concret : Camion.
    public creerTransport(): Transport {
        return new Camion();
    }
}

class LogistiqueMer extends Logistique {
    // Implémentation de la Factory Method pour un produit concret : Bateau.
    public creerTransport(): Transport {
        return new Bateau();
    }
}

// 5. Code client
function codeClient(logistique: Logistique) {
    console.log(logistique.planifierLivraison());
}

// Utilisation
console.log('--- Client utilisant la logistique route ---');
codeClient(new LogistiqueRoute()); // Affiche : "Planification logistique : Livraison par la route..."

console.log('\n--- Client utilisant la logistique mer ---');
codeClient(new LogistiqueMer());   // Affiche : "Planification logistique : Livraison par la mer..."

Le pouvoir est là : Le client (codeClient) et la classe de base (Logistique) ne connaissent pas les classes Camion ou Bateau. Ils ne dépendent que de l'interface Transport. L'instanciation concrète est repoussée dans les sous-classes. Pour ajouter un nouveau mode de transport (e.g., Avion), on crée un nouveau ProduitConcret et une nouvelle sous-classe de Logistique. Le code existant n'est pas modifié (principe OCP).

Comparaison avec Abstract Factory

C'est une question qui tue. Souvent confondus.

AspectFactory MethodAbstract Factory
But principalDéléguer l'instanciation d'un seul produit à une sous-classe.Créer des familles d'objets liés ou dépendants sans spécifier leurs classes concrètes.
MécanismeHéritage. La sous-classe redéfinit une méthode qui crée un objet.Composition. Un objet (l'usine) possède plusieurs méthodes de création, chacune pour un type de produit différent.
ÉchelleMéthode unique, souvent centrée sur un type de produit.Interface avec plusieurs Factory Methods, une par type de produit dans la famille.
FlexibilitéRelativement simple. Ajoute un nouveau produit en créant une nouvelle sous-classe de créateur.Plus complexe. Pour ajouter un nouveau type de produit, il faut modifier l'interface de l'Abstract Factory et toutes ses implémentations.
RelationC'est souvent un bloc de construction utilisé à l'intérieur d'une Abstract Factory. Chaque méthode d'une Abstract Factory peut être une Factory Method.Généralise et orchestre plusieurs créations.

En résumé :

  • Factory Method : « Je laisse ma sous-classe décider quel objet unique créer. »
  • Abstract Factory : « Je fournis une interface pour créer toute une famille d'objets liés. Ce sera à d'autres classes (concrètes) de l'implémenter. »

La Factory Method, c'est l'indicateur discret qui vous file le bon contact dans le bon quartier. L'Abstract Factory, c'est le réseau entier.


Je repoussai mon clavier. La Factory Method avait la beauté des choses simples et profondes. Elle ne résolvait pas tout, mais elle établissait un principe : séparer la logique d'utilisation de la logique d'instanciation.

C'était un pas de plus vers l'indépendance des modules. Un pas loin du new couplé, un pas vers le polymorphisme et l'extensibilité.

Le prochain sur la liste serait son grand frère, plus complexe, plus puissant : Abstract Factory. Le patron qui contrôle plusieurs fournisseurs à la fois.

Mais pour l'instant, la Factory Method restait là, élégante et efficace, rappelant qu'en conception, parfois, le pouvoir se trouve à savoir déléguer.