Menu
Coddy logo textTech

Patrón Command

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 70 de 87.

El Patrón Command es un patrón de diseño de comportamiento que convierte una solicitud en un objeto independiente que contiene toda la información sobre la solicitud. Esta transformación le permite pasar solicitudes como argumentos de método, retrasar o poner en cola la ejecución de una solicitud y admitir operaciones que se pueden deshacer.

Piénsalo como un restaurante: en lugar de decirle directamente al chef qué cocinar, escribes tu pedido en una nota. El camarero (invoker) lleva la nota (command) a la cocina, donde puede ser encolada, priorizada o incluso cancelada. El patrón desacopla el objeto que invoca la operación del que la realiza.

El patrón tiene cuatro componentes clave: una interfaz Command que declara el método execute, clases ConcreteCommand que implementan acciones específicas, un Receiver que realiza el trabajo real y un Invoker que activa los comandos:

interface Command {
    void execute();
}
class Light {  // Receptor
    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 {  // Invocador
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
    }
}

El invocador no sabe qué acción se realizará; simplemente llama a execute():

Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();  // Salida: La luz está encendida

El patrón Command sobresale cuando se necesita encolar operaciones, implementar la funcionalidad de deshacer/rehacer o programar tareas para su ejecución posterior. Cada comando encapsula todo lo necesario para realizar una acción, lo que hace que su sistema sea más flexible y extensible.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de automatización del hogar inteligente utilizando el Patrón Command! Crearás un sistema donde varios dispositivos del hogar pueden ser controlados a través de comandos, permitiendo que las acciones sean puestas en cola, ejecutadas e incluso almacenadas para su uso posterior, tal como un control remoto universal que no necesita saber cómo funciona internamente cada dispositivo.

Organizarás tu código en cuatro archivos:

  • Command.java: Define la interfaz Command que implementarán todos los comandos de los dispositivos. Debe declarar un único método execute() que realice la acción del comando.
  • Devices.java: Crea dos clases receptoras que representen dispositivos del hogar inteligente:

    Television - tiene los métodos powerOn() que imprime "TV is now ON", powerOff() que imprime "TV is now OFF", y setChannel(int channel) que imprime "TV channel set to " + channel.

    Thermostat - tiene los métodos setTemperature(int temp) que imprime "Thermostat set to " + temp + " degrees" y turnOff() que imprime "Thermostat turned OFF".

  • Commands.java: Crea clases de comandos concretos que encapsulen las operaciones de los dispositivos:

    TVOnCommand - recibe una Television en su constructor y llama a powerOn() cuando se ejecuta.

    TVOffCommand - recibe una Television en su constructor y llama a powerOff() cuando se ejecuta.

    TVChannelCommand - recibe una Television y un int channel en su constructor, y llama a setChannel() con ese canal cuando se ejecuta.

    ThermostatSetCommand - recibe un Thermostat y un int temperature en su constructor, y llama a setTemperature() con ese valor cuando se ejecuta.

  • Main.java: Crea una clase RemoteControl (el invocador) que tenga un método setCommand(Command cmd) para almacenar un comando y pressButton() para ejecutar el comando almacenado.

    En tu método principal, recibirás dos entradas: un número de canal de TV (entero) y una temperatura de termostato (entero).

    Crea una Television y un Thermostat. Crea un RemoteControl y demuestra el Patrón Command mediante:

    1. Configurar un TVOnCommand y presionar el botón
    2. Configurar un TVChannelCommand con tu canal de entrada y presionar el botón
    3. Configurar un ThermostatSetCommand con tu temperatura de entrada y presionar el botón
    4. Configurar un TVOffCommand y presionar el botón

Recibirás dos entradas en orden: el canal de TV (entero) y la temperatura del termostato (entero).

Por ejemplo, con las entradas 5 y 72, tu salida sería:

TV is now ON
TV channel set to 5
Thermostat set to 72 degrees
TV is now OFF

¡Observa cómo el RemoteControl nunca interactúa directamente con los dispositivos; solo conoce la interfaz Command! Cada comando encapsula todo lo necesario para realizar su acción, lo que facilita agregar nuevos dispositivos y comandos sin cambiar el invocador.

Hoja de referencia

El Patrón Command es un patrón de diseño de comportamiento que encapsula una solicitud como un objeto, lo que permite parametrizar clientes con diferentes solicitudes, encolar o registrar solicitudes y admitir operaciones que se pueden deshacer.

El patrón desacopla el objeto que invoca la operación (invocador) del que la realiza (receptor).

Componentes Clave

  • Command: Interfaz que declara el método execute()
  • ConcreteCommand: Clases que implementan acciones específicas
  • Receiver: Objeto que realiza el trabajo real
  • Invoker: Objeto que activa los comandos

Estructura Básica

// Interfaz Command
interface Command {
    void execute();
}

// Receptor
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();
    }
}

// Invocador
class RemoteControl {
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
    }
}

Uso

Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();  // Salida: Light is ON

El invocador no sabe qué acción se realizará; simplemente llama a execute(). Esto hace que el sistema sea flexible y extensible, ideal para encolar operaciones, implementar la funcionalidad de deshacer/rehacer o programar tareas.

Pruébalo tú mismo

import java.util.Scanner;

// TODO: Crear la clase RemoteControl (el invocador) con:
// - método setCommand(Command cmd) para almacenar un comando
// - método pressButton() para ejecutar el comando almacenado

class RemoteControl {
    // TODO: Implementar RemoteControl
}

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Leer las entradas
        int channel = scanner.nextInt();
        int temperature = scanner.nextInt();
        
        // TODO: Crear una Television y un Thermostat
        
        // TODO: Crear un RemoteControl
        
        // TODO: Demostrar el Command Pattern:
        // 1. Configurar un TVOnCommand y presionar el botón
        // 2. Configurar un TVChannelCommand con el canal de entrada y presionar el botón
        // 3. Configurar un ThermostatSetCommand con la temperatura de entrada y presionar el botón
        // 4. Configurar un TVOffCommand y presionar el botón
        
        scanner.close();
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos