Le design pattern Command est un modèle de conception qui permet d’encapsuler une requête en tant qu’objet. Il permet de séparer les objets qui émettent les requêtes des objets qui les exécutent, ce qui offre une plus grande flexibilité et un couplage plus faible entre les différents composants de l’application.
En utilisant le design pattern Command, les clients peuvent paramétrer les objets qui exécutent les requêtes avec différentes requêtes, les annuler ou les enregistrer pour une utilisation ultérieure. Il est souvent utilisé dans les applications qui nécessitent des fonctionnalités de journalisation pour enregistrer les actions de l’utilisateur.
Problème
Le design pattern Command résout le problème de couplage fort entre les objets émetteurs de requêtes et les objets qui exécutent ces requêtes dans une application. En effet, dans une application traditionnelle, un objet émetteur de requête doit avoir une connaissance directe de l’objet qui exécute la requête. Cela peut conduire à un couplage fort entre les deux objets, ce qui rend difficile la réutilisation et la flexibilité de l’application.
En utilisant le design pattern Command, le couplage entre les objets émetteurs de requêtes et les objets qui exécutent ces requêtes est réduit. Les requêtes sont encapsulées dans des objets Command, qui sont ensuite utilisés par les objets émetteurs de requêtes pour exécuter les requêtes. Cela permet aux objets émetteurs de requêtes de paramétrer les objets qui exécutent les requêtes avec différentes requêtes, de les annuler, de les enregistrer pour une utilisation ultérieure, et de combiner différentes requêtes pour créer des fonctionnalités plus complexes.
En résumé, le design pattern Command permet de rendre une application plus flexible et plus modulaire en réduisant le couplage entre les objets émetteurs de requêtes et les objets qui exécutent ces requêtes.
Solution
En PHP, le design pattern Command peut être utilisé pour encapsuler des requêtes en tant qu’objets, permettant ainsi de créer des commandes réutilisables et modulaires. Les objets Command peuvent être paramétrés avec différentes requêtes, ce qui permet une plus grande flexibilité dans l’application.
Pour implémenter le design pattern Command en PHP, il est recommandé de créer une interface Command qui définit une méthode execute(). Les différentes classes Command implémentent ensuite cette interface et fournissent leur propre implémentation de la méthode execute() pour exécuter la requête spécifique.
Les objets émetteurs de requêtes créent ensuite des objets Command et les passent à un objet Invoker, qui est responsable d’exécuter les commandes. L’objet Invoker peut également enregistrer les commandes dans une file d’attente, les annuler ou les répéter en fonction des besoins de l’application.
Le design pattern Command peut également être combiné avec d’autres design patterns, tels que le pattern Composite pour créer des fonctionnalités plus complexes.
En utilisant le design pattern Command en PHP, les développeurs peuvent créer des applications plus modulaires, flexibles et faciles à maintenir. Les commandes peuvent être facilement ajoutées, modifiées ou supprimées sans affecter le reste de l’application, ce qui permet une plus grande évolutivité et une meilleure gestion du code.
Analogie
Une analogie pour le design pattern Command serait celle d’un restaurant. Imaginez que vous êtes un serveur dans un restaurant et que vous prenez les commandes des clients. Plutôt que d’aller directement en cuisine pour donner les instructions de chaque commande, vous prenez d’abord les commandes sur un bloc-notes. Ces commandes sur le bloc-notes sont des objets Command qui encapsulent les requêtes des clients.
Ensuite, vous transmettez le bloc-notes au chef cuisinier, qui est l’objet Invoker. Le chef cuisinier est responsable d’exécuter les commandes et de préparer les plats demandés par les clients en suivant les instructions écrites sur le bloc-notes.
Si un client veut ajouter une commande ou annuler une commande, vous pouvez facilement modifier le bloc-notes sans perturber le processus de préparation des autres commandes en cours. En fin de compte, toutes les commandes du bloc-notes seront exécutées et les plats seront servis aux clients.
Cette analogie montre comment le design pattern Command permet de séparer les objets qui émettent les requêtes des objets qui les exécutent, ce qui rend le système plus flexible et plus facile à gérer.
Implémentation
Voici une méthodologie générale pour implémenter le design pattern Command :
- Identifier les parties de votre application qui pourraient bénéficier de l’utilisation du design pattern Command. Cherchez les cas où les actions doivent être traitées de manière flexible et modulaire.
- Créer une interface Command qui définit une méthode execute(). Cette interface peut être utilisée par toutes les classes de commande pour garantir une structure cohérente.
- Implémenter les classes de commande qui correspondent aux actions spécifiques que vous souhaitez encapsuler en tant qu’objet Command. Chaque classe de commande doit implémenter l’interface Command et fournir une implémentation pour la méthode execute().
- Créer un objet émetteur de requêtes qui crée des objets Command et les transmet à un objet Invoker. L’objet Invoker sera responsable d’exécuter les commandes.
- Implémenter un objet Invoker qui exécute les commandes en appelant leur méthode execute(). L’objet Invoker peut également enregistrer les commandes dans une file d’attente, les annuler ou les répéter en fonction des besoins de l’application.
- Tester votre implémentation pour vous assurer qu’elle fonctionne correctement et qu’elle est capable de traiter les actions de manière flexible et modulaire.
Il est important de noter que cette méthodologie est générale et qu’elle peut être adaptée en fonction des besoins spécifiques de votre application. En utilisant cette méthodologie, vous devriez être en mesure de mettre en place le design pattern Command dans votre application de manière efficace et structurée.
Supposons qu’on a un système de commande de repas pour un restaurant. Le restaurant propose plusieurs types de plats (par exemple, des pizzas, des pâtes, des hamburgers, etc.) et les clients peuvent commander plusieurs plats à la fois. On veut implémenter un système qui permet de stocker les commandes sous forme d’objets Command, de les afficher et de les exécuter.
Tout d’abord, on crée une interface Command qui définit une méthode execute() :
interface Command {
public function execute(): void;
}
Ensuite, on crée une classe de commande pour chaque type de plat. Chaque classe doit implémenter l’interface Command et fournir une implémentation pour la méthode execute(). Par exemple, voici la classe PizzaCommand :
class PizzaCommand implements Command {
private string $size;
private array $toppings;
public function __construct(string $size, array $toppings) {
$this->size = $size;
$this->toppings = $toppings;
}
public function execute(): void {
// Code pour préparer et servir la pizza avec la taille et les ingrédients spécifiés
echo "Pizza " . $this->size . " avec " . implode(", ", $this->toppings) . " a été préparée et servie.\n";
}
}
On peut créer des classes similaires pour les autres types de plats (par exemple, PastaCommand, HamburgerCommand, etc.).
Ensuite, on crée une classe Invoker (dans notre exemple la class Waiter) qui stocke une liste de commandes et qui est responsable de les exécuter. La méthode takeOrder() permet d’ajouter des commandes à la liste, et la méthode sendOrdersToKitchen() parcourt la liste et appelle la méthode execute() de chaque commande.
class Waiter {
private array $orders = [];
public function takeOrder(Command $command): void {
$this->orders[] = $command;
}
public function showOrders(): void {
foreach ($this->orders as $order) {
echo "- ";
$order->execute();
}
}
public function sendOrdersToKitchen(): void {
foreach ($this->orders as $order) {
$order->execute();
}
$this->orders = []; // On vide la liste des commandes après exécution
}
}
Enfin, on peut créer une instance de l’objet Waiter, ajouter des instances de commandes à la liste d’ordres et exécuter les commandes à l’aide de la méthode sendOrdersToKitchen(). Par exemple :
$waiter = new Waiter();
$order1 = new PizzaCommand("petite", ["mozzarella", "tomates", "basilic"]);
$order2 = new PastaCommand("spaghetti", "carbonara");
$order3 = new HamburgerCommand("boeuf", ["cheddar", "oignon", "ketchup"]);
$waiter->takeOrder($order1);
$waiter->takeOrder($order2);
$waiter->takeOrder($order3);
$waiter->showOrders();
// - Pizza petite avec mozzarella, tomates, basilic a été préparée et servie.
// - Pizza grande avec champignons, viande hachée, pecorino a été préparée et servie.