El patrón de diseño Command es un patrón de comportamiento que convierte una solicitud en un objeto, lo que permite parametrizar a los clientes con diferentes solicitudes, encolar o registrar solicitudes y soportar operaciones que se pueden deshacer. Este patrón es especialmente útil para implementar operaciones que se pueden deshacer y rehacer, como en aplicaciones de edición.

Conceptos Clave

  1. Command: Declara una interfaz para ejecutar una operación.
  2. ConcreteCommand: Implementa la interfaz Command y define una relación entre el receptor y una acción.
  3. Client: Crea un objeto ConcreteCommand y establece su receptor.
  4. Invoker: Pide al objeto Command que ejecute la solicitud.
  5. Receiver: Sabe cómo realizar las operaciones asociadas a llevar a cabo una solicitud. Cualquier clase puede actuar como un receptor.

Estructura

La estructura del patrón Command se puede representar de la siguiente manera:

Client --> Invoker --> Command --> ConcreteCommand --> Receiver

Ejemplo Práctico

Vamos a implementar un ejemplo simple de un editor de texto que puede deshacer y rehacer operaciones de texto.

Paso 1: Definir la Interfaz Command

// Command.java
public interface Command {
    void execute();
    void undo();
}

Paso 2: Crear ConcreteCommand

// WriteCommand.java
public class WriteCommand implements Command {
    private String text;
    private StringBuilder document;

    public WriteCommand(StringBuilder document, String text) {
        this.document = document;
        this.text = text;
    }

    @Override
    public void execute() {
        document.append(text);
    }

    @Override
    public void undo() {
        document.delete(document.length() - text.length(), document.length());
    }
}

Paso 3: Crear Invoker

// TextEditor.java
import java.util.Stack;

public class TextEditor {
    private StringBuilder document = new StringBuilder();
    private Stack<Command> commandHistory = new Stack<>();

    public void write(String text) {
        Command command = new WriteCommand(document, text);
        command.execute();
        commandHistory.push(command);
    }

    public void undo() {
        if (!commandHistory.isEmpty()) {
            Command command = commandHistory.pop();
            command.undo();
        }
    }

    public String getText() {
        return document.toString();
    }
}

Paso 4: Uso del Patrón Command

// Main.java
public class Main {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        editor.write("Hello, ");
        editor.write("world!");
        System.out.println(editor.getText()); // Output: Hello, world!

        editor.undo();
        System.out.println(editor.getText()); // Output: Hello, 
    }
}

Ejercicio Práctico

Ejercicio 1

Implementa un comando adicional para borrar texto en el editor. Define una nueva clase DeleteCommand que implemente la interfaz Command.

Solución

// DeleteCommand.java
public class DeleteCommand implements Command {
    private StringBuilder document;
    private String deletedText;
    private int length;

    public DeleteCommand(StringBuilder document, int length) {
        this.document = document;
        this.length = length;
    }

    @Override
    public void execute() {
        int start = document.length() - length;
        deletedText = document.substring(start);
        document.delete(start, document.length());
    }

    @Override
    public void undo() {
        document.append(deletedText);
    }
}

Ejercicio 2

Modifica la clase TextEditor para soportar el nuevo comando DeleteCommand.

Solución

// TextEditor.java
public class TextEditor {
    private StringBuilder document = new StringBuilder();
    private Stack<Command> commandHistory = new Stack<>();

    public void write(String text) {
        Command command = new WriteCommand(document, text);
        command.execute();
        commandHistory.push(command);
    }

    public void delete(int length) {
        Command command = new DeleteCommand(document, length);
        command.execute();
        commandHistory.push(command);
    }

    public void undo() {
        if (!commandHistory.isEmpty()) {
            Command command = commandHistory.pop();
            command.undo();
        }
    }

    public String getText() {
        return document.toString();
    }
}

Uso del Nuevo Comando

// Main.java
public class Main {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        editor.write("Hello, ");
        editor.write("world!");
        System.out.println(editor.getText()); // Output: Hello, world!

        editor.delete(6);
        System.out.println(editor.getText()); // Output: Hello,

        editor.undo();
        System.out.println(editor.getText()); // Output: Hello, world!
    }
}

Resumen

El patrón Command es una poderosa herramienta para encapsular solicitudes como objetos, permitiendo operaciones como deshacer y rehacer. En este módulo, hemos cubierto la estructura básica del patrón, implementado un ejemplo práctico y extendido la funcionalidad con ejercicios adicionales. Este patrón es especialmente útil en aplicaciones donde las operaciones necesitan ser registradas, deshechas o encadenadas.

© Copyright 2024. Todos los derechos reservados