Les développeurs d'applications Laravel sont incités à abandonner le mot-clé new au sein de leurs contrôleurs pour adopter le pattern Factory Method. En déplaçant la création d'objets dans des factories dédiées, le code devient plus facile à étendre, à tester et à maintenir — des avantages cruciaux à mesure que les projets dépassent le stade de quelques simples points de terminaison (endpoints).

Pourquoi le mot-clé new est un risque caché

Lorsqu'un contrôleur contient une ligne telle que

$processor = new StripePaymentProcessor($config);

le contrôleur est désormais étroitement couplé à la classe StripePaymentProcessor. Chaque endroit nécessitant un processeur de paiement répète cette ligne, éparpillant la logique de construction à travers toute la base de code. Si le processeur nécessite ultérieurement un logger, un gestionnaire de cache ou un format de configuration différent, chacun de ces points devra être mis à jour. Le résultat est un code fragile qui résiste au changement et qui est difficile à simuler (mock) lors des tests unitaires.

L'intervention du pattern Factory Method

Le pattern Factory Method remplace l'instanciation directe par une méthode qui renvoie une instance d'une interface donnée. Le contrôleur dépend de l'interface, tandis qu'une classe factory sait quelle classe concrète construire et comment assembler ses dépendances. Toute la logique de création réside à un seul endroit, de sorte que l'ajout d'une nouvelle dépendance ou le remplacement d'implémentations ne modifie que la factory.

Avantages principaux

  • Couplage faible – Les contrôleurs travaillent avec des abstractions, pas des classes concrètes.
  • Construction centralisée – Modifier le processus de construction nécessite la modification d'un seul fichier.
  • Testabilité – Les factories peuvent être simulées (stubbed) ou remplacées par des mocks, permettant des tests de contrôleurs isolés.
  • Principe Ouvert/Fermé – De nouvelles fonctionnalités (par exemple, une nouvelle passerelle de paiement) peuvent être ajoutées sans toucher au code existant du contrôleur.

Une analogie avec un café

Imaginez un barista qui doit moudre les grains, faire mousser le lait et verser l'eau manuellement pour chaque commande, en utilisant une longue série d'instructions if-else. Si la recette du latte change, chaque barista doit réapprendre les étapes. Une machine à café qui reçoit un type de commande et gère la préparation en interne résout le problème : le barista indique simplement à la machine ce qui est nécessaire, et la machine encapsule toutes les étapes. Mettre à jour la recette signifie désormais ajuster la machine, et non chaque barista.

Laravel s'appuie déjà sur les factories

Les composants de base de Laravel illustrent ce pattern en action :

  • Database – ConnectionFactory décide de construire une connexion MySQL ou PostgreSQL.
  • Queues – QueueManager crée des drivers pour Redis, SQS ou d'autres back-ends.
  • Filesystem – FilesystemManager produit des instances de disques locaux ou S3.
  • Mail – MailManager résout les drivers SMTP, Mailgun ou d'autres drivers de messagerie.

Si le framework fait confiance aux factories pour ces services critiques, le code personnalisé devrait faire de même.

Quand introduire une factory

Utilisez une factory quand :

  • La création d'objets implique plusieurs étapes de configuration ou des services externes.
  • Plusieurs implémentations interchangeables existent (différentes passerelles de paiement, fournisseurs de stockage, etc.).
  • La liste des implémentations possibles est susceptible de s'allonger.

Évitez une factory quand :

  • La construction est un simple appel new immuable sans configuration supplémentaire.
  • Une seule implémentation sera utilisée, rendant l'abstraction supplémentaire inutile (overhead).

Guide rapide : refactorisation d'un contrôleur de paiement

  1. Définissez une interface – PaymentProcessorInterface avec une méthode process(array $data).
  2. Implémentez des classes concrètes – StripePaymentProcessor, PayPalPaymentProcessor, chacune respectant l'interface.
  3. Créez une factory – PaymentProcessorFactory avec une méthode make(string $driver): PaymentProcessorInterface. À l'intérieur, utilisez un switch ou une map pour renvoyer la classe appropriée, en injectant les services requis depuis le conteneur de services de Laravel.
  4. Injectez la factory – Dans le constructeur du contrôleur, utilisez le type-hint PaymentProcessorFactory. Laravel la résoudra automatiquement.
  5. Utilisez la factory – $processor = $this->processorFactory->make('stripe'); $processor->process($request->all());

Désormais, le contrôleur ne mentionne jamais new ni de processeur concret. Ajouter une nouvelle passerelle signifie créer une classe et étendre la map de la factory — aucun changement n'est nécessaire dans le contrôleur.

Inconvénients potentiels et comment les atténuer

La principale critique des factories est l'indirection ajoutée, ce qui peut sembler verbeux pour des objets triviaux. Sur-concevoir un service simple peut gonfler la base de code sans réel bénéfice. La clé est d'évaluer la complexité de la construction : si un objet est un simple conteneur de données sans dépendances, un new direct peut être acceptable. De plus, les factories peuvent devenir un dépotoir pour une logique non liée. Maintenir les factories concentrées sur la création d'objets et déléguer la configuration à des service providers dédiés préserve la clarté.

À surveiller ensuite

  • Liaisons du conteneur de services (Service container bindings) – Le conteneur de Laravel peut résoudre les factories automatiquement si vous liez l'interface à la classe de la factory dans un service provider.
  • Auto-discovery – Certains packages exposent leurs propres factories ; soyez attentifs aux collisions de noms.
  • Stratégies de test – Lors des tests unitaires de contrôleurs, remplacez la factory par un mock qui renvoie un processeur simulé (stub), garantissant que les tests restent rapides et isolés.

L'essentiel

Remplacer les appels new éparpillés par une factory bien placée centralise la construction, réduit le couplage et aligne le code personnalisé sur la philosophie de conception de Laravel. Pour les équipes qui anticipent une croissance — nouveaux fournisseurs de paiement, back-ends de stockage ou tout composant de type plug-in — le pattern Factory Method est un investissement à faible coût qui se traduit par une flexibilité et une confiance accrues. Votre futur vous-même, ainsi que toute personne héritant du code, vous en remerciera.