Patrón Command
Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy. Lección 56 de 70.
El patrón Command es un patrón de comportamiento que convierte una solicitud en un objeto independiente que contiene toda la información sobre la solicitud. Esta transformación te permite pasar solicitudes como argumentos de métodos, ponerlas en cola, registrarlas o admitir operaciones que se pueden deshacer.
El patrón separa el objeto que invoca una operación del objeto que sabe cómo realizarla. Consta de cuatro componentes clave: una interfaz de comando, comandos concretos, un receptor (el objeto que realiza el trabajo real) y un invocador (el objeto que activa los comandos).
public interface ICommand
{
void Execute();
}
public class Light // Receptor
{
public void TurnOn() => Console.WriteLine("Light is ON");
public void TurnOff() => Console.WriteLine("Light is OFF");
}
public class TurnOnCommand : ICommand
{
private Light _light;
public TurnOnCommand(Light light) => _light = light;
public void Execute() => _light.TurnOn();
}
public class TurnOffCommand : ICommand
{
private Light _light;
public TurnOffCommand(Light light) => _light = light;
public void Execute() => _light.TurnOff();
}El invocador almacena y ejecuta comandos sin saber qué hacen:
public class RemoteControl // Invocador
{
private ICommand _command;
public void SetCommand(ICommand command) => _command = command;
public void PressButton() => _command.Execute();
}
// Uso
var light = new Light();
var remote = new RemoteControl();
remote.SetCommand(new TurnOnCommand(light));
remote.PressButton(); // La luz está ENCENDIDA
remote.SetCommand(new TurnOffCommand(light));
remote.PressButton(); // La luz está APAGADAEl patrón Command es especialmente potente para implementar la funcionalidad de deshacer, la grabación de macros o la puesta en cola de operaciones para ejecutarlas más adelante. Cada comando encapsula todo lo necesario para realizar una acción, lo que hace que tu sistema sea más flexible y extensible.
Desafío
FácilConstruyamos un sistema de comandos para un editor de texto utilizando el patrón Command. Crearás un sistema en el que las operaciones de edición, como insertar y eliminar texto, estén encapsuladas como objetos de comando, lo que permitirá al editor ejecutarlas mediante una interfaz unificada.
Organizarás tu código en tres archivos:
Command.cs: Define una interfazICommanden el espacio de nombresTextEditorcon un único métodoExecute(). Después, crea dos clases de comando concretas:InsertCommand: recibe unDocumenty una cadenatexten su constructor. Al ejecutarse, agrega el texto al documento e imprimeInserted: {text}DeleteCommand: recibe unDocumenty unint counten su constructor. Al ejecutarse, elimina los últimoscountcaracteres del documento e imprimeDeleted: {count} characters
Document.cs: Crea una claseDocumenten el mismo espacio de nombres. Este es tu receptor: el objeto que realmente realiza las operaciones de texto. Debe tener:- Un campo privado de tipo string para almacenar el contenido (inicializado como una cadena vacía)
- Un método
Append(string text)que agrega texto al contenido - Un método
RemoveLast(int count)que elimina los últimoscountcaracteres (si count supera la longitud del contenido, borra todo el contenido) - Un método
GetContent()que devuelve el contenido actual
Program.cs: Crea una claseEditorque actúe como invocador. Debe tener un métodoSetCommand(ICommand command)y un métodoExecuteCommand()que ejecute el comando actual. En tu código principal, demuestra el patrón Command procesando una serie de operaciones de edición.
Recibirás las siguientes entradas:
- Número de comandos que se ejecutarán
- Para cada comando: el tipo de comando (
insertodelete) seguido del texto que se insertará o del número de caracteres que se eliminarán
Después de ejecutar todos los comandos, imprime el contenido final del documento en una línea nueva con el formato Content: {content}.
Por ejemplo, si las entradas son:
4
insert
Hello
insert
World
delete
3
insert
!La salida debería ser:
Inserted: Hello
Inserted: World
Deleted: 3 characters
Inserted: !
Content: Hello Wo!Observa cómo Editor (el invocador) no sabe nada sobre la manipulación de texto: simplemente ejecuta cualquier comando que recibe. Los comandos encapsulan tanto la acción como el receptor, lo que facilita agregar nuevas operaciones como ReplaceCommand sin cambiar el editor.
Pruébalo tú mismo
using System;
using TextEditor;
// TODO: Crea la clase Editor (el invoker)
public class Editor
{
// TODO: Añade un campo privado para almacenar el comando actual
private ICommand _command;
// TODO: Implementa el método SetCommand
public void SetCommand(ICommand command)
{
// TODO: Almacena el comando
}
// TODO: Implementa el método ExecuteCommand
public void ExecuteCommand()
{
// TODO: Ejecuta el comando actual
}
}
class Program
{
public static void Main(string[] args)
{
// Lee el número de comandos
int n = Convert.ToInt32(Console.ReadLine());
// Crea el documento (receiver)
Document document = new Document();
// Crea el editor (invoker)
Editor editor = new Editor();
// TODO: Procesa cada comando
for (int i = 0; i < n; i++)
{
string commandType = Console.ReadLine();
// TODO: Basado en commandType, crea el comando apropiado
// - Si es "insert": lee el texto y crea InsertCommand
// - Si es "delete": lee la cantidad y crea DeleteCommand
// Luego establece el comando en el editor y ejecútalo
}
// TODO: Imprime el contenido final con el formato "Content: {content}"
}
}
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
1Fundamentos de OOP
Archivos externosNamespaces y directivasIntro a clases y objetosLa palabra clave 'this'Métodos y parámetrosCampos vs PropiedadesConstructoresInicializadores de objetosResumen - Calculadora simple4Herencia
Sintaxis básica de herencia (:)La palabra clave 'base'Palabras clave Virtual y OverrideClases selladas (Sealed)La clase base 'object'Resumen: Jerarquía de empleados7Características avanzadas
Sobrecarga de operadoresIndexadores (this[])Sobrescritura de ToString()Métodos de extensiónResumen - Lista personalizada10Patrones de diseño - Parte 1
Introducción a los patrones de diseñoSingleton Thread-SafePatrón FactoryPatrón Observer (Eventos)Patrón Strategy2Propiedades y miembros estáticos
Propiedades autoimplementadasPropiedades de solo lectura y escrituraCampos y métodos estáticosClases estáticasMiembros con cuerpo de expresión5Polimorfismo e Interfaces
Polimorfismo: Compilación vs. EjecuciónInterfaz vs. Clase AbstractaInterfaces MúltiplesInterfaces ExplícitasUpcasting y DowncastingRepaso: Calculadora de Figuras8Conceptos avanzados de POO
Composición sobre herenciaGenéricos (clases y métodos)Delegados y eventosAtributos y ReflexiónIDisposable y la sentencia usingFundamentos de Inyección de dependencias11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Arquitectura de clases
Datos de instancia vs. estáticosPalabras clave 'readonly' y 'const'Campos de respaldoResumen - Gestor de cuentas bancarias6Encapsulamiento
Modificadores de accesoPropiedades para el encapsulamientoImplementación de ocultamiento de datosPatrones de inmutabilidadRepaso - Registros de estudiantesPractica por tu cuenta: Compilador de C# online