El patrón Command (comando, orden) encapsula una petición en un objeto. Esto permite parametrizar métodos con diferentes solicitudes, retrasar o poner en cola la ejecución de una solicitud, y soportar operaciones de deshacer.
Suena complicado?? Bueno, es mucho más simple… supongamos que queremos ejecutar una acción (login de usuario), lo que hacemos es crear un objeto comando que tenga la información necesaria para que el manejador (handler) pueda realizar esta tarea.
El patrón Command resuelve varios problemas:
El patrón Command propone las siguientes soluciones:
Este patrón es recomendable cuando:
Desacoplamiento: Reduce el acoplamiento entre la clase que invoca la operación y la que sabe cómo ejecutarla.
Extensibilidad: Facilita agregar nuevos comandos sin cambiar el código existente.
Flexibilidad: Permite realizar operaciones más complejas, como colas de comandos y operaciones deshacer/rehacer.
Complejidad Adicional: Puede aumentar la complejidad del código al introducir varias clases y objetos.
Sobrecarga: Si cada acción simple se convierte en un comando, puede resultar en una sobrecarga de clases y objetos.
Debemos crear un sistema de automatización del hogar, que permite a los usuarios controlar una variedad de dispositivos electrónicos del hogar, como luces, termostatos y sistemas de seguridad, a través de una interfaz de usuario centralizada.
Necesitamos enviar comandos a los dispositivos de una manera flexible y extensible.
Los comandos pueden variar en su complejidad y pueden requerir acciones como activar, desactivar, ajustar la temperatura, o establecer modos de seguridad.
Además, el sistema debe ser capaz de soportar nuevos tipos de comandos en el futuro sin modificar el código central de la aplicación.
Elegimos usar el patrón Command porque nos permite encapsular todas las solicitudes en objetos de comando individuales. Esto no solo permite la parametrización y la ejecución de comandos, sino que también facilita la adición de nuevos comandos a medida que se introducen nuevos dispositivos y funcionalidades.
Definimos la interfaz Command que representa las acciones ejecutables como objetos. Creamos clases concretas LightOnCommand y LightOffCommand que implementan Command y encapsulan la funcionalidad de encender y apagar las luces, actuando como comandos específicos. Un Receiver, la clase Light, es el objeto que tiene la lógica de negocio para realizar las acciones. Un Invoker, representado por la clase RemoteControl, es responsable de iniciar los comandos. Finalmente, el cliente, la clase SmartHomeApp, crea los comandos y los asigna al invocador para que sean ejecutados.
Codificamos en Java lo que preparamos en el diagrama.
Creamos la Interfaz Command:
interface Command {
void execute();
}
Implementamos los ConcreteCommands:
// Comandos para controlar las luces
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOff();
}
}
// Otros comandos concretos para diferentes dispositivos pueden ser definidos aquí
Definimos el Receiver:
class Light {
public void turnOn() {
System.out.println("La luz está encendida.");
}
public void turnOff() {
System.out.println("La luz está apagada.");
}
}
// Clases adicionales para otros dispositivos pueden ser definidas aquí
Creamos el Invoker:
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
El código cliente:
public class SmartHomeApp {
public static void main(String[] args) {
Light livingRoomLight = new Light();
Command lightOn = new LightOnCommand(livingRoomLight);
Command lightOff = new LightOffCommand(livingRoomLight);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();
remote.setCommand(lightOff);
remote.pressButton();
}
}
Los participantes que vimos antes son: Command, ConcreteCommand, Receiver, Invoker, Client:
Este ejemplo muestra cómo usar el patrón Command para crear un sistema de automatización del hogar. Este diseño facilita la extensión del sistema para incluir más tipos de comandos y dispositivos, manteniendo un acoplamiento débil entre el emisor de la solicitud y el receptor, el que realiza la acción.
Puede ser usado para mantener el estado necesario para deshacer operaciones.
Los comandos pueden ensamblarse en estructuras compuestas para operaciones más complejas.