Mediator Pattern
- Type : Comportemental
- Difficulté : 7/10
- Définition succincte : Le Mediator Pattern est un design pattern comportemental qui centralise la communication entre plusieurs objets, déléguant cette communication à un objet "médiateur". Il permet de réduire les dépendances directes entre les objets et de simplifier leur interaction.
Objectif du Mediator Pattern
L'objectif du Mediator Pattern est de réduire les dépendances directes entre plusieurs objets devant interagir, en centralisant leur communication via un médiateur. Cela permet de rendre le système plus flexible et de simplifier la gestion des interactions complexes.
Implémentation avec Laravel
Prenons un exemple où nous développons un système de chat dans Laravel. Le médiateur gère l'envoi des messages entre les utilisateurs. En plus de cette gestion, le médiateur enverra des notifications lorsque l'utilisateur qui envoie le message est un administrateur, illustrant une interaction avec plusieurs modules.
a) Créer l'interface ChatMediator (Mediator)
Le médiateur est responsable de la gestion des interactions entre les utilisateurs (ou colleagues).
// app/Contracts/ChatMediator.php
namespace App\Contracts;
interface ChatMediator
{
public function sendMessage(string $message, UserColleague $user): void;
public function addUser(UserColleague $user): void;
}
b) Implémenter le médiateur concret ConcreteChatMediator (ConcreteMediator)
Le médiateur gère la communication entre les utilisateurs et inclut une logique supplémentaire pour envoyer une notification si un administrateur envoie un message.
// app/Services/ConcreteChatMediator.php
namespace App\Services;
use App\Contracts\ChatMediator;
use App\Contracts\UserColleague;
use Illuminate\Support\Facades\Log;
class ConcreteChatMediator implements ChatMediator
{
protected $users = [];
// Ajouter un utilisateur au chat
public function addUser(UserColleague $user): void
{
$this->users[] = $user;
}
// Envoyer un message à tous les utilisateurs sauf l'expéditeur et gérer la notification admin
public function sendMessage(string $message, UserColleague $user): void
{
// Logique de notification si l'utilisateur est un administrateur
if ($user->isAdmin()) {
$this->notifyAdminMessage($user, $message);
}
// Envoyer le message à tous les utilisateurs
foreach ($this->users as $u) {
if ($u !== $user) {
$u->receiveMessage($message);
}
}
}
// Logique pour notifier lorsqu'un administrateur envoie un message
protected function notifyAdminMessage(UserColleague $admin, string $message): void
{
// Envoi d'une notification (dans ce cas, simplement affiché)
Log::info("Admin {$admin->getName()} sent a message: {$message}");
echo "Notification: Admin {$admin->getName()} sent a message: '{$message}'" . PHP_EOL;
}
}
c) Créer l'interface UserColleague (Colleague)
Les utilisateurs participant au chat doivent implémenter cette interface pour interagir avec le médiateur.
// app/Contracts/UserColleague.php
namespace App\Contracts;
interface UserColleague
{
public function sendMessage(string $message): void;
public function receiveMessage(string $message): void;
public function isAdmin(): bool;
public function getName(): string;
}
d) Implémenter les utilisateurs concrets ChatUser (ConcreteColleague)
Chaque utilisateur envoie et reçoit des messages via le médiateur. Nous ajoutons un attribut pour identifier si un utilisateur est un administrateur.
// app/Services/ChatUser.php
namespace App\Services;
use App\Contracts\ChatMediator;
use App\Contracts\UserColleague;
class ChatUser implements UserColleague
{
protected $name;
protected $mediator;
protected $isAdmin;
public function __construct(string $name, ChatMediator $mediator, bool $isAdmin = false)
{
$this->name = $name;
$this->mediator = $mediator;
$this->isAdmin = $isAdmin;
}
public function sendMessage(string $message): void
{
echo "{$this->name} sends: {$message}" . PHP_EOL;
$this->mediator->sendMessage($message, $this);
}
public function receiveMessage(string $message): void
{
echo "{$this->name} receives: {$message}" . PHP_EOL;
}
public function isAdmin(): bool
{
return $this->isAdmin;
}
public function getName(): string
{
return $this->name;
}
}
e) Utilisation du Mediator Pattern dans une commande artisan
Nous allons créer une commande artisan pour simuler une conversation dans un chat, avec la gestion de notifications lorsque l'administrateur envoie un message.
// app/Console/Commands/ChatSimulation.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\ConcreteChatMediator;
use App\Services\ChatUser;
class ChatSimulation extends Command
{
protected $signature = 'chat:simulate';
protected $description = 'Simule une conversation avec notification lorsqu\'un administrateur envoie un message';
public function handle()
{
// Créer le médiateur
$mediator = new ConcreteChatMediator();
// Créer des utilisateurs (incluant un administrateur)
$user1 = new ChatUser('Alice', $mediator);
$user2 = new ChatUser('Bob', $mediator, true); // Bob est admin
$user3 = new ChatUser('Charlie', $mediator);
// Ajouter les utilisateurs au médiateur
$mediator->addUser($user1);
$mediator->addUser($user2);
$mediator->addUser($user3);
// Simuler l'envoi de messages
$user1->sendMessage("Hello everyone!");
$user2->sendMessage("Admin message: Welcome to the group.");
$user3->sendMessage("Hi all!");
}
}
f) Exécution de la commande
Exécute cette commande pour simuler une conversation avec des notifications pour les messages de l'administrateur.
php artisan chat:simulate
Résultat attendu
Alice sends: Hello everyone!
Bob receives: Hello everyone!
Charlie receives: Hello everyone!
Bob sends: Admin message: Welcome to the group.
Notification: Admin Bob sent a message: 'Admin message: Welcome to the group.'
Alice receives: Admin message: Welcome to the group.
Charlie receives: Admin message: Welcome to the group.
Charlie sends: Hi all!
Alice receives: Hi all!
Bob receives: Hi all!
Avantages du Mediator Pattern
- Réduction du couplage : Les objets communiquent via le médiateur, réduisant les dépendances directes et rendant le système plus flexible.
- Centralisation des interactions : Le médiateur gère la communication et la logique additionnelle, facilitant la gestion des interactions complexes (comme les notifications).
- Extensibilité : Il est facile d'ajouter de nouveaux comportements ou objets sans modifier les autres participants.
Conclusion
Le Mediator Pattern centralise la communication et les interactions complexes entre les objets, comme dans ce système de chat où le médiateur gère les messages et envoie des notifications pour les messages d'un administrateur. Ce pattern permet de structurer les interactions de manière flexible et modulaire, en simplifiant la gestion des multiples interactions entre composants.