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
- Command: Declara una interfaz para ejecutar una operación.
- ConcreteCommand: Implementa la interfaz Command y define una relación entre el receptor y una acción.
- Client: Crea un objeto ConcreteCommand y establece su receptor.
- Invoker: Pide al objeto Command que ejecute la solicitud.
- 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:
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
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.
Curso de Patrones de Diseño de Software
Módulo 1: Introducción a los Patrones de Diseño
- ¿Qué son los Patrones de Diseño?
- Historia y Origen de los Patrones de Diseño
- Clasificación de los Patrones de Diseño
- Ventajas y Desventajas de Usar Patrones de Diseño
Módulo 2: Patrones Creacionales
- Introducción a los Patrones Creacionales
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
Módulo 3: Patrones Estructurales
Módulo 4: Patrones de Comportamiento
- Introducción a los Patrones de Comportamiento
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Módulo 5: Aplicación de Patrones de Diseño
- Cómo Seleccionar el Patrón Adecuado
- Ejemplos Prácticos de Uso de Patrones
- Patrones de Diseño en Proyectos Reales
- Refactorización Usando Patrones de Diseño
Módulo 6: Patrones de Diseño Avanzados
- Patrones de Diseño en Arquitecturas Modernas
- Patrones de Diseño en Microservicios
- Patrones de Diseño en Sistemas Distribuidos
- Patrones de Diseño en Desarrollo Ágil