Factory Pattern
- Type : Créationnel
- Difficulté : 3/10
- Définition succincte : Le Factory Pattern est un design pattern de création qui fournit une interface pour créer des objets sans spécifier la classe exacte de l'objet à instancier. Il permet de centraliser la création d'objets en utilisant une factory qui décide quel type d'objet créer en fonction de la demande. Contrairement au Factory Method Pattern, où chaque sous-classe décide comment instancier un produit, ici, une seule classe (la factory) gère l'instanciation de plusieurs types d'objets.
- Contexte spécifique à Laravel : En Laravel, le Factory Pattern est souvent utilisé dans les Service Providers pour créer des services ou des objets à la volée via le conteneur de services. Laravel utilise aussi une version simplifiée de ce pattern dans les Container Bindings et les Service Providers pour gérer des dépendances.
Objectif du Factory Pattern
L'objectif principal du Factory Pattern est de centraliser la création d'objets en utilisant une seule classe, sans que le code client ait à connaître la classe concrète instanciée. Cela permet de gérer la création d'objets de manière flexible, selon les besoins du système.
Structure du Factory Pattern
- Product : Interface ou classe abstraite qui définit le type d'objet à créer.
- ConcreteProduct : Classe concrète qui implémente ou hérite de
Product, c'est l'objet créé par la factory. - Factory : Classe qui encapsule la logique de création des objets et décide quel
ConcreteProductinstancier.
1. Exemple d'utilisation dans Laravel
Dans Laravel, le Factory Pattern est utilisé dans les Service Providers pour enregistrer des services. Un exemple simple serait l'utilisation du conteneur de services pour créer des services dynamiquement :
$this->app->bind('PaymentService', function ($app) {
return new \App\Services\PaymentService();
});
Ici, la méthode bind agit comme une factory pour créer des services en fonction des besoins de l'application.
2. Implémentation complète dans Laravel
Imaginons que tu développes une application où différents types de notifications doivent être envoyées (par e-mail, SMS, ou push notification). Le Factory Pattern te permet de centraliser la création des services de notification et de gérer les différentes stratégies d'envoi sans exposer les détails au code client.
a) Définir l'interface Notification
Tu commences par définir une interface qui sert de contrat pour tous les types de notifications.
// app/Contracts/NotificationInterface.php
namespace App\Contracts;
interface NotificationInterface
{
public function send($message): string;
}
b) Créer les classes concrètes de notification
Ensuite, tu implémentes différentes classes de notification qui respectent l'interface NotificationInterface.
2.1. Classe EmailNotification
// app/Notifications/EmailNotification.php
namespace App\Notifications;
use App\Contracts\NotificationInterface;
class EmailNotification implements NotificationInterface
{
public function send($message): string
{
return "Email sent: " . $message;
}
}
2.2. Classe SmsNotification
// app/Notifications/SmsNotification.php
namespace App\Notifications;
use App\Contracts\NotificationInterface;
class SmsNotification implements NotificationInterface
{
public function send($message): string
{
return "SMS sent: " . $message;
}
}
2.3. Classe PushNotification
// app/Notifications/PushNotification.php
namespace App\Notifications;
use App\Contracts\NotificationInterface;
class PushNotification implements NotificationInterface
{
public function send($message): string
{
return "Push notification sent: " . $message;
}
}
c) Créer la NotificationFactory
Voici la factory qui va décider quelle classe de notification instancier en fonction du type de notification à envoyer.
// app/Factories/NotificationFactory.php
namespace App\Factories;
use App\Contracts\NotificationInterface;
use App\Notifications\EmailNotification;
use App\Notifications\SmsNotification;
use App\Notifications\PushNotification;
class NotificationFactory
{
public static function create($type): NotificationInterface
{
return match($type) {
'email' => new EmailNotification(),
'sms' => new SmsNotification(),
'push' => new PushNotification(),
default => throw new \Exception("Notification type not supported"),
};
}
}
d) Utiliser le Factory Pattern dans une commande CLI
Voici une commande CLI qui utilise la NotificationFactory pour envoyer différentes types de notifications.
// app/Console/Commands/SendNotification.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Factories\NotificationFactory;
class SendNotification extends Command
{
protected $signature = 'notification:send {type} {message}';
protected $description = 'Send a notification of a specific type';
public function handle()
{
$type = $this->argument('type');
$message = $this->argument('message');
try {
$notificationService = NotificationFactory::create($type);
$result = $notificationService->send($message);
$this->info($result);
} catch (\Exception $e) {
$this->error($e->getMessage());
}
}
}
e) Exécuter la commande
Voici quelques exemples de commandes pour tester les différents types de notifications :
php artisan notification:send email "Hello, this is an email!"
Renvoie :
Email sent: Hello, this is an email!
php artisan notification:send sms "This is an SMS!"
Renvoie :
SMS sent: This is an SMS!
php artisan notification:send push "This is a push notification!"
Renvoie :
Push notification sent: This is a push notification!
Exemple de résultat
En exécutant les différentes commandes avec les types email, sms, ou push, tu verras que la factory génère dynamiquement le bon type de notification et envoie le message spécifié.
Avantages du Factory Pattern
- Centralisation de la création : La création d'objets est centralisée dans une factory, ce qui facilite l'ajout ou la modification de la logique de création.
- Simplification du code client : Le client n'a pas besoin de connaître les classes concrètes qu'il utilise. Il ne fait que demander un type de notification, et la factory se charge du reste.
- Extensibilité : Ajouter un nouveau type de notification est simple. Il suffit de créer une nouvelle classe et de l'intégrer dans la factory.
Inconvénients du Factory Pattern
- Multiplication des classes : Comme pour beaucoup de patterns de création, la factory peut entraîner la création de nombreuses classes, ce qui peut compliquer la gestion du projet.
- Surcharge de la factory : Si la factory doit gérer trop de types d'objets différents, elle peut devenir difficile à maintenir et à comprendre.
Conclusion
Le Factory Pattern est un excellent moyen de centraliser la création d'objets et de masquer la complexité d'instanciation au code client. En Laravel, ce pattern est couramment utilisé dans les Service Providers pour gérer des services partagés, mais il peut aussi être implémenté manuellement pour des scénarios spécifiques comme dans cet exemple avec des notifications. Il rend le système plus flexible et extensible, tout en maintenant un haut degré de simplicité côté client.