Bridge Pattern
- Type : Structurel
- Difficulté : 7/10
- Définition succincte : Le Bridge Pattern est un design pattern structurel qui permet de découpler une abstraction de son implémentation, afin que les deux puissent évoluer indépendamment. Ce pattern est utile lorsque tu veux éviter le couplage rigide entre l'abstraction (interface ou classe abstraite) et ses implémentations concrètes, permettant ainsi d'étendre l'un ou l'autre sans affecter l'autre partie.
Objectif du Bridge Pattern
L'objectif du Bridge Pattern est de séparer une abstraction d'une implémentation afin de réduire le couplage entre elles. Ce pattern permet d'étendre à la fois l'abstraction et ses implémentations de manière indépendante, sans que les changements de l'un n'affectent l'autre. C'est une solution idéale pour éviter la prolifération des sous-classes et pour simplifier les systèmes où plusieurs implémentations d'une abstraction sont nécessaires.
Structure du Bridge Pattern
- Abstraction : Interface ou classe abstraite qui définit des méthodes haut niveau.
- Refined Abstraction : Sous-classe ou implémentation concrète de l'abstraction.
- Implementor : Interface pour la partie implémentation spécifique.
- Concrete Implementor : Classes concrètes qui implémentent l'interface Implementor.
Implémentation avec Laravel
Prenons un exemple dans une application Laravel où tu dois gérer différents systèmes de notifications (comme email, SMS, et push notification). L'objectif est de permettre d'ajouter de nouveaux types de notifications sans modifier le système existant. Le Bridge Pattern te permet de séparer la logique de la notification (abstraction) de l'implémentation technique spécifique à chaque type de notification (implémentation).
a) Créer l'interface NotificationSender (Implementor)
L'interface NotificationSender définit les méthodes communes que chaque implémentation de notification (email, SMS, push) doit respecter.
// app/Contracts/NotificationSender.php
namespace App\Contracts;
interface NotificationSender
{
public function send(string $message): void;
}
b) Créer les implémentations concrètes de NotificationSender (Concrete Implementor)
1. Classe EmailNotification
Cette classe implémente l'envoi de notifications par email.
// app/Services/EmailNotification.php
namespace App\Services;
use App\Contracts\NotificationSender;
class EmailNotification implements NotificationSender
{
public function send(string $message): void
{
echo "Envoi d'un email : {$message}" . PHP_EOL;
}
}
2. Classe SmsNotification
Cette classe implémente l'envoi de notifications par SMS.
// app/Services/SmsNotification.php
namespace App\Services;
use App\Contracts\NotificationSender;
class SmsNotification implements NotificationSender
{
public function send(string $message): void
{
echo "Envoi d'un SMS : {$message}" . PHP_EOL;
}
}
3. Classe PushNotification
Cette classe implémente l'envoi de notifications via des notifications push.
// app/Services/PushNotification.php
namespace App\Services;
use App\Contracts\NotificationSender;
class PushNotification implements NotificationSender
{
public function send(string $message): void
{
echo "Envoi d'une notification push : {$message}" . PHP_EOL;
}
}
c) Créer l'abstraction Notification (Abstraction)
L'abstraction Notification permet de séparer la logique de gestion des notifications de leur implémentation technique. Elle utilise une instance de NotificationSender pour envoyer les messages.
// app/Notifications/Notification.php
namespace App\Notifications;
use App\Contracts\NotificationSender;
abstract class Notification
{
protected $sender;
public function __construct(NotificationSender $sender)
{
$this->sender = $sender;
}
abstract public function notify(string $message): void;
}
d) Créer des notifications concrètes (Refined Abstraction)
Nous allons maintenant créer des classes concrètes de notifications, comme une alerte utilisateur ou une notification système, qui dépendent du type de notification utilisé (email, SMS, push).
1. Classe UserAlertNotification
Cette classe représente une alerte utilisateur et utilise le type de notification choisi pour envoyer le message.
// app/Notifications/UserAlertNotification.php
namespace App\Notifications;
class UserAlertNotification extends Notification
{
public function notify(string $message): void
{
$this->sender->send("Alerte utilisateur : {$message}");
}
}
2. Classe SystemNotification
Cette classe représente une notification système.
// app/Notifications/SystemNotification.php
namespace App\Notifications;
class SystemNotification extends Notification
{
public function notify(string $message): void
{
$this->sender->send("Notification système : {$message}");
}
}
e) Utilisation du Bridge Pattern dans une commande CLI
Nous allons maintenant créer une commande CLI pour tester les différents types de notifications avec leurs implémentations respectives.
1. Commande SendNotification
Cette commande simule l'envoi de notifications via différents canaux (email, SMS, push) pour différents types de notifications (alerte utilisateur, notification système).
// app/Console/Commands/SendNotification.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\EmailNotification;
use App\Services\SmsNotification;
use App\Services\PushNotification;
use App\Notifications\UserAlertNotification;
use App\Notifications\SystemNotification;
class SendNotification extends Command
{
protected $signature = 'notification:send';
protected $description = 'Envoi de notifications via différents canaux';
public function handle()
{
// Envoi d'une alerte utilisateur via email
$emailNotification = new EmailNotification();
$userAlert = new UserAlertNotification($emailNotification);
$userAlert->notify('Votre compte a été mis à jour.');
// Envoi d'une alerte utilisateur via SMS
$smsNotification = new SmsNotification();
$userAlert = new UserAlertNotification($smsNotification);
$userAlert->notify('Votre mot de passe a été modifié.');
// Envoi d'une notification système via Push
$pushNotification = new PushNotification();
$systemNotification = new SystemNotification($pushNotification);
$systemNotification->notify('Le serveur est en panne.');
}
}
f) Exécution de la commande
Tu peux exécuter la commande pour envoyer différentes notifications via différents canaux :
php artisan notification:send
Résultat attendu :
Envoi d'un email : Alerte utilisateur : Votre compte a été mis à jour.
Envoi d'un SMS : Alerte utilisateur : Votre mot de passe a été modifié.
Envoi d'une notification push : Notification système : Le serveur est en panne.
Avantages du Bridge Pattern
- Séparation des responsabilités : Le Bridge Pattern permet de séparer l'abstraction de l'implémentation, rendant les deux parties indépendantes et plus faciles à maintenir.
- Extensibilité : Ce pattern facilite l'ajout de nouvelles implémentations (par exemple, un nouveau type de notification) sans modifier l'abstraction.
- Réduction de la prolifération des classes : Plutôt que d'avoir une multitude de sous-classes pour chaque combinaison d'abstraction et d'implémentation, le Bridge Pattern permet de les combiner de manière flexible.
Inconvénients du Bridge Pattern
- Complexité accrue : Ce pattern peut ajouter une complexité inutile si le nombre d'abstractions ou d'implémentations est faible, car il nécessite la création de plusieurs classes supplémentaires.
- Difficulté de mise en place initiale : La séparation entre l'abstraction et l'implémentation peut sembler difficile à mettre en œuvre dans les petites applications, surtout si la structure n'est pas complexe au départ.
Conclusion
Le Bridge Pattern est une solution efficace pour gérer des systèmes où l'abstraction et l'implémentation doivent évoluer indépendamment l'une de l'autre. En Laravel, ce pattern peut être utilisé dans des systèmes comme les notifications, les services de paiement, ou les systèmes de fichiers, où différentes implémentations doivent être interchangeables. Il améliore la modularité et permet une extension plus facile du code, tout en maintenant une séparation claire des responsabilités.