Introducció al Patró Command
El patró Command és un patró de disseny de comportament que converteix una sol·licitud en un objecte autònom que conté tota la informació sobre la sol·licitud. Aquest patró permet parametritzar els mètodes amb sol·licituds, posar sol·licituds en cua o registrar sol·licituds, i suportar operacions desfer.
Objectius del Patró Command
- Encapsulació de sol·licituds: Permet encapsular una sol·licitud com un objecte, permetent així que es puguin passar sol·licituds com a arguments de mètodes.
- Desacoblament: Desacobla l'objecte que invoca l'operació de l'objecte que realitza l'operació.
- Historial i desfer: Permet mantenir un historial de sol·licituds i possibilita la funcionalitat de desfer.
Components del Patró Command
- Command: Interfície que declara un mètode per executar una operació.
- ConcreteCommand: Implementa la interfície Command i defineix la relació entre el receptor i una acció.
- Client: Crea un objecte ConcreteCommand i estableix el seu receptor.
- Invoker: Demana a l'objecte Command que executi la sol·licitud.
- Receiver: Sap com dur a terme les operacions associades a la sol·licitud.
Diagrama UML del Patró Command
+----------------+ +----------------+ +----------------+ | Client | | Invoker | | Receiver | +----------------+ +----------------+ +----------------+ | | | | | | | | | v v v +----------------+ +----------------+ +----------------+ | Command |<-----| ConcreteCommand|----->| Receiver | +----------------+ +----------------+ +----------------+ |+ execute() | |+ execute() | |+ action() | +----------------+ +----------------+ +----------------+
Exemple Pràctic
Escenari
Suposem que estem desenvolupant una aplicació de control remot per a dispositius electrònics. Volem encapsular les sol·licituds d'encesa i apagat dels dispositius en objectes de comanda.
Implementació en Java
Interfície Command
Classe Receiver
public class Light { public void turnOn() { System.out.println("The light is on"); } public void turnOff() { System.out.println("The light is off"); } }
Classes ConcreteCommand
public class TurnOnLightCommand implements Command { private Light light; public TurnOnLightCommand(Light light) { this.light = light; } @Override public void execute() { light.turnOn(); } } public class TurnOffLightCommand implements Command { private Light light; public TurnOffLightCommand(Light light) { this.light = light; } @Override public void execute() { light.turnOff(); } }
Classe Invoker
public class RemoteControl { private Command command; public void setCommand(Command command) { this.command = command; } public void pressButton() { command.execute(); } }
Classe Client
public class Client { public static void main(String[] args) { Light light = new Light(); Command turnOn = new TurnOnLightCommand(light); Command turnOff = new TurnOffLightCommand(light); RemoteControl remote = new RemoteControl(); remote.setCommand(turnOn); remote.pressButton(); remote.setCommand(turnOff); remote.pressButton(); } }
Explicació del Codi
- Interfície Command: Defineix el mètode
execute()
que serà implementat per les comandes concretes. - Receiver (Light): Conté les operacions que es poden executar (encendre i apagar la llum).
- ConcreteCommand (TurnOnLightCommand i TurnOffLightCommand): Implementen la interfície
Command
i encapsulen les sol·licituds per encendre i apagar la llum. - Invoker (RemoteControl): Manté una referència a un objecte
Command
i invoca el mètodeexecute()
quan es prem el botó. - Client: Configura els objectes
Command
iReceiver
, i passa les comandes a l'Invoker
per a la seva execució.
Exercici Pràctic
Enunciat
Implementa un sistema de control remot per a un ventilador que pugui encendre, apagar i ajustar la velocitat del ventilador. Utilitza el patró Command per encapsular aquestes sol·licituds.
Solució Proposada
Interfície Command
Classe Receiver
public class Fan { public void turnOn() { System.out.println("The fan is on"); } public void turnOff() { System.out.println("The fan is off"); } public void setSpeed(int speed) { System.out.println("The fan speed is set to " + speed); } }
Classes ConcreteCommand
public class TurnOnFanCommand implements Command { private Fan fan; public TurnOnFanCommand(Fan fan) { this.fan = fan; } @Override public void execute() { fan.turnOn(); } } public class TurnOffFanCommand implements Command { private Fan fan; public TurnOffFanCommand(Fan fan) { this.fan = fan; } @Override public void execute() { fan.turnOff(); } } public class SetFanSpeedCommand implements Command { private Fan fan; private int speed; public SetFanSpeedCommand(Fan fan, int speed) { this.fan = fan; this.speed = speed; } @Override public void execute() { fan.setSpeed(speed); } }
Classe Invoker
public class RemoteControl { private Command command; public void setCommand(Command command) { this.command = command; } public void pressButton() { command.execute(); } }
Classe Client
public class Client { public static void main(String[] args) { Fan fan = new Fan(); Command turnOn = new TurnOnFanCommand(fan); Command turnOff = new TurnOffFanCommand(fan); Command setSpeed = new SetFanSpeedCommand(fan, 3); RemoteControl remote = new RemoteControl(); remote.setCommand(turnOn); remote.pressButton(); remote.setCommand(setSpeed); remote.pressButton(); remote.setCommand(turnOff); remote.pressButton(); } }
Errors Comuns i Consells
- No encapsular tota la informació necessària: Assegura't que els objectes
Command
encapsulin tota la informació necessària per executar la sol·licitud. - No desacoblar correctament: Recorda que l'objectiu principal del patró Command és desacoblar l'emissor de la sol·licitud del receptor de la sol·licitud.
- No implementar la interfície Command: Totes les comandes concretes han d'implementar la interfície
Command
.
Resum
El patró Command és una eina poderosa per encapsular sol·licituds com a objectes, permetent una major flexibilitat i desacoblament en el disseny del programari. Aquest patró és especialment útil per implementar funcionalitats com desfer, historial de sol·licituds i cues de sol·licituds. Amb una comprensió sòlida del patró Command, els desenvolupadors poden crear sistemes més modulars i mantenibles.
Curs de Patrons de Disseny de Programari
Mòdul 1: Introducció als Patrons de Disseny
- Què són els Patrons de Disseny?
- Història i Origen dels Patrons de Disseny
- Classificació dels Patrons de Disseny
- Avantatges i Desavantatges d'Usar Patrons de Disseny
Mòdul 2: Patrons Creacionals
Mòdul 3: Patrons Estructurals
Mòdul 4: Patrons de Comportament
- Introducció als Patrons de Comportament
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Mòdul 5: Aplicació de Patrons de Disseny
- Com Seleccionar el Patró Adequat
- Exemples Pràctics d'Ús de Patrons
- Patrons de Disseny en Projectes Reals
- Refactorització Usant Patrons de Disseny
Mòdul 6: Patrons de Disseny Avançats
- Patrons de Disseny en Arquitectures Modernes
- Patrons de Disseny en Microserveis
- Patrons de Disseny en Sistemes Distribuïts
- Patrons de Disseny en Desenvolupament Àgil