Menu
Coddy logo textTech

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 le permite pasar solicitudes como argumentos de método, 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á APAGADA

El patrón Command es particularmente potente para implementar la funcionalidad de deshacer, la grabación de macros o el encolado de operaciones 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 comandos para un editor de texto utilizando el patrón Command. Crearás un sistema donde las operaciones de edición, como insertar y eliminar texto, se encapsulan como objetos de comando, permitiendo que el editor los ejecute a través de una interfaz unificada.

Organizarás tu código en tres archivos:

  • Command.cs: Define una interfaz ICommand en el espacio de nombres TextEditor con un único método Execute(). Luego, crea dos clases de comando concretas:
    • InsertCommand: recibe un Document y un string text en su constructor. Cuando se ejecuta, añade el texto al documento e imprime Inserted: {text}
    • DeleteCommand: recibe un Document y un int count en su constructor. Cuando se ejecuta, elimina los últimos count caracteres del documento e imprime Deleted: {count} characters
  • Document.cs: Crea una clase Document en el mismo espacio de nombres. Este es tu receptor (receiver): el objeto que realmente realiza las operaciones de texto. Debe tener:
    • Un campo de cadena privado para almacenar el contenido (inicializado como una cadena vacía)
    • Un método Append(string text) que añade texto al contenido
    • Un método RemoveLast(int count) que elimina los últimos count caracteres (si count excede la longitud del contenido, borra todo el contenido)
    • Un método GetContent() que devuelve el contenido actual
  • Program.cs: Crea una clase Editor que actúe como el invocador (invoker). Debe tener un método SetCommand(ICommand command) y un método ExecuteCommand() 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 a ejecutar
  • Para cada comando: el tipo de comando (insert o delete) seguido del texto a insertar o el número de caracteres a eliminar

Después de ejecutar todos los comandos, imprime el contenido final del documento en una nueva línea 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 el Editor (invocador) no sabe nada sobre la manipulación de texto; simplemente ejecuta cualquier comando que se le asigne. Los comandos encapsulan tanto la acción como el receptor, lo que facilita la adición de nuevas operaciones como ReplaceCommand sin cambiar el editor.

Hoja de referencia

El patrón Command es un patrón de comportamiento que encapsula una solicitud como un objeto independiente que contiene toda la información sobre dicha solicitud. Esto permite pasar solicitudes como argumentos de método, encolarlas, registrarlas o admitir operaciones que se pueden deshacer.

El patrón tiene cuatro componentes clave:

  • Interfaz Command: define el método Execute().
  • Comandos concretos: implementan la interfaz de comando y encapsulan acciones específicas.
  • Receptor (Receiver): el objeto que realiza el trabajo real.
  • Invocador (Invoker): el objeto que activa los comandos sin conocer su implementación.

Interfaz Command y Comandos Concretos

public interface ICommand
{
    void Execute();
}

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

Receptor (Receiver)

public class Light
{
    public void TurnOn() => Console.WriteLine("Light is ON");
    public void TurnOff() => Console.WriteLine("Light is OFF");
}

Invocador (Invoker)

public class RemoteControl
{
    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();  // Light is ON

remote.SetCommand(new TurnOffCommand(light));
remote.PressButton();  // Light is OFF

El patrón Command es útil para implementar la funcionalidad de deshacer, la grabación de macros o la puesta en cola de operaciones para su ejecución posterior. Cada comando encapsula todo lo necesario para realizar una acción, lo que hace que los sistemas sean más flexibles y extensibles.

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}"
    }
}
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