Patron Commande
Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 70 sur 87.
Le Patron Commande est un patron de conception comportemental qui transforme une requête en un objet autonome contenant toutes les informations sur cette requête. Cette transformation vous permet de passer des requêtes comme arguments de méthode, de retarder ou de mettre en file d'attente l'exécution d'une requête, et de prendre en charge des opérations annulables.
Pensez-y comme à un restaurant : au lieu de dire directement au chef quoi cuisiner, vous écrivez votre commande sur un bon. Le serveur (invoker) apporte le bon (command) à la cuisine, où il peut être mis en file d'attente, priorisé ou même annulé. Ce patron de conception découple l'objet qui invoque l'opération de celui qui l'exécute.
Le patron comporte quatre composants clés : une interface Command déclarant la méthode execute, des classes ConcreteCommand qui implémentent des actions spécifiques, un Receiver qui effectue le travail réel, et un Invoker qui déclenche les commandes :
interface Command {
void execute();
}class Light { // Récepteur
public void turnOn() {
System.out.println("Light is ON");
}
public void turnOff() {
System.out.println("Light is OFF");
}
}class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
}class RemoteControl { // Appelant
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}L'appelant ne sait pas quelle action sera effectuée — il appelle simplement execute() :
Light light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // Sortie : La lumière est ALLUMÉELe patron de conception Commande (Command Pattern) excelle lorsque vous devez mettre des opérations en file d'attente, implémenter une fonctionnalité d'annulation/rétablissement, ou planifier des tâches pour une exécution ultérieure. Chaque commande encapsule tout ce qui est nécessaire pour effectuer une action, rendant votre système plus flexible et extensible.
Défi
FacileConstruisons un système d'automatisation de maison intelligente en utilisant le Command Pattern ! Vous allez créer un système où divers appareils domestiques peuvent être contrôlés par des commandes, permettant aux actions d'être mises en file d'attente, exécutées et même stockées pour une utilisation ultérieure — tout comme une télécommande universelle qui n'a pas besoin de savoir comment chaque appareil fonctionne en interne.
Vous organiserez votre code sur quatre fichiers :
Command.java: Définissez l'interfaceCommandque toutes les commandes d'appareils implémenteront. Elle doit déclarer une seule méthodeexecute()qui effectue l'action de la commande.Devices.java: Créez deux classes réceptrices qui représentent les appareils de la maison intelligente :Television- possède les méthodespowerOn()qui affiche"TV is now ON",powerOff()qui affiche"TV is now OFF", etsetChannel(int channel)qui affiche"TV channel set to " + channel.Thermostat- possède les méthodessetTemperature(int temp)qui affiche"Thermostat set to " + temp + " degrees"etturnOff()qui affiche"Thermostat turned OFF".Commands.java: Créez des classes de commandes concrètes qui encapsulent les opérations des appareils :TVOnCommand- prend uneTelevisiondans son constructeur et appellepowerOn()lors de l'exécution.TVOffCommand- prend uneTelevisiondans son constructeur et appellepowerOff()lors de l'exécution.TVChannelCommand- prend uneTelevisionet unint channeldans son constructeur, et appellesetChannel()avec ce canal lors de l'exécution.ThermostatSetCommand- prend unThermostatet unint temperaturedans son constructeur, et appellesetTemperature()avec cette valeur lors de l'exécution.Main.java: Créez une classeRemoteControl(l'invocateur) qui possède une méthodesetCommand(Command cmd)pour stocker une commande etpressButton()pour exécuter la commande stockée.Dans votre méthode principale, vous recevrez deux entrées : un numéro de chaîne de télévision (entier) et une température de thermostat (entier).
Créez une
Televisionet unThermostat. Créez uneRemoteControlet démontrez le Command Pattern en :- Définissant une
TVOnCommandet en appuyant sur le bouton - Définissant une
TVChannelCommandavec votre canal d'entrée et en appuyant sur le bouton - Définissant une
ThermostatSetCommandavec votre température d'entrée et en appuyant sur le bouton - Définissant une
TVOffCommandet en appuyant sur le bouton
- Définissant une
Vous recevrez deux entrées dans l'ordre : le canal TV (entier) et la température du thermostat (entier).
Par exemple, avec les entrées 5 et 72, votre sortie serait :
TV is now ON
TV channel set to 5
Thermostat set to 72 degrees
TV is now OFFRemarquez comment la RemoteControl n'interagit jamais directement avec les appareils — elle ne connaît que l'interface Command. Chaque commande encapsule tout ce qui est nécessaire pour effectuer son action, ce qui facilite l'ajout de nouveaux appareils et de nouvelles commandes sans modifier l'invocateur !
Aide-mémoire
Le Command Pattern (ou patron de commande) est un patron de conception comportemental qui encapsule une requête sous la forme d'un objet, vous permettant ainsi de paramétrer des clients avec différentes requêtes, de mettre en file d'attente ou de journaliser des requêtes, et de prendre en charge des opérations annulables.
Ce patron découple l'objet qui invoque l'opération (invoker) de celui qui l'exécute (receiver).
Composants clés
- Command : Interface déclarant la méthode
execute() - ConcreteCommand : Classes implémentant des actions spécifiques
- Receiver : Objet qui effectue le travail réel
- Invoker : Objet qui déclenche les commandes
Structure de base
// Interface Command
interface Command {
void execute();
}
// Receiver
class Light {
public void turnOn() {
System.out.println("Light is ON");
}
public void turnOff() {
System.out.println("Light is OFF");
}
}
// ConcreteCommand
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
}
// Invoker
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}Utilisation
Light light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton(); // Résultat : Light is ONL'appelant (invoker) ne sait pas quelle action sera effectuée — il appelle simplement execute(). Cela rend le système flexible et extensible, idéal pour mettre en file d'attente des opérations, implémenter des fonctionnalités d'annulation/rétablissement (undo/redo) ou planifier des tâches.
Essayez vous-même
import java.util.Scanner;
// TODO: Créer la classe RemoteControl (l'invocateur) avec :
// - la méthode setCommand(Command cmd) pour stocker une commande
// - la méthode pressButton() pour exécuter la commande stockée
class RemoteControl {
// TODO: Implémenter RemoteControl
}
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Lire les entrées
int channel = scanner.nextInt();
int temperature = scanner.nextInt();
// TODO: Créer une Television et un Thermostat
// TODO: Créer une RemoteControl
// TODO: Démontrer le Command Pattern :
// 1. Définir une TVOnCommand et appuyer sur le bouton
// 2. Définir une TVChannelCommand avec le canal d'entrée et appuyer sur le bouton
// 3. Définir une ThermostatSetCommand avec la température d'entrée et appuyer sur le bouton
// 4. Définir une TVOffCommand et appuyer sur le bouton
scanner.close();
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesChamps (Attributs)Méthode constructeurSurcharge de constructeurRécapitulatif - Calculatrice simple4Héritage
Héritage de base (extends)Le mot-clé superRedéfinition de méthode (@Override)Chaînage de constructeursLa classe ObjectHéritage simple et multiniveauPourquoi pas d'héritage multiple de classesRécapitulatif - Hiérarchie des employés7Méthodes spéciales et classe Object
Méthode toString()equals() et hashCode()Méthode clone()compareTo() et ComparableInterface ComparatorRécapitulatif - Tri personnalisé2Modificateurs d'accès et Encapsulation
Aperçu des niveaux d'accèsMéthodes Getter et SetterMasquage d'informationsLe mot-clé finalRécapitulatif - Gestionnaire de compte bancaire5Polymorphisme
Bases de la surcharge de méthodesRedéfinition de méthodes (Run-Time)Upcasting et DowncastingL'opérateur instanceofClasses et méthodes abstraitesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageAgrégation vs CompositionClasses internes, imbriquées et anonymesEnums et méthodes d'EnumRecords (Java 16+)Classes scellées (Java 17+)11Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron MonteurPatron ObservateurPatron Stratégie3Propriétés de classe et membres statiques
Variables d'instance vs variables statiquesMéthodes statiquesBlocs statiquesConstantes (static final)Récapitulatif - Compteur et utilitaire6Interfaces et Classes Abstraites
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesDefault et Static dans les InterfacesClasses Abstraites vs InterfacesInterfaces FonctionnellesRécapitulatif - Système de Paiement9La généricité
Introduction à la généricitéClasses génériquesMéthodes génériquesParamètres de type bornésWildcards (?, extends, super)Récapitulatif - Conteneur générique12Patrons de conception, partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositePatron Itérateur