Menu
Coddy logo textTech

Padrão Command

Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy — lição 56 de 70.

O padrão Command é um padrão comportamental que transforma uma solicitação em um objeto independente que contém todas as informações sobre a solicitação. Essa transformação permite que você passe solicitações como argumentos de método, coloque-as em fila, registre-as ou ofereça suporte a operações que podem ser desfeitas.

O padrão separa o objeto que invoca uma operação do objeto que sabe como executá-la. Ele consiste em quatro componentes principais: uma interface de comando, comandos concretos, um receptor (o objeto que realiza o trabalho real) e um invocador (o objeto que dispara os 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();
}

O invoker armazena e executa comandos sem saber o que eles fazem:

public class RemoteControl  // Invoker
{
    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();  // A luz está LIGADA

remote.SetCommand(new TurnOffCommand(light));
remote.PressButton();  // A luz está DESLIGADA

O padrão Command é particularmente poderoso para implementar a funcionalidade de desfazer, gravação de macros ou enfileiramento de operações para execução posterior. Cada comando encapsula tudo o que é necessário para realizar uma ação, tornando seu sistema mais flexível e extensível.

challenge icon

Desafio

Fácil

Vamos construir um sistema de comandos para um editor de texto usando o padrão Command. Você criará um sistema onde operações de edição, como inserir e excluir texto, são encapsuladas como objetos de comando, permitindo que o editor as execute por meio de uma interface unificada.

Você organizará seu código em três arquivos:

  • Command.cs: Defina uma interface ICommand no namespace TextEditor com um único método Execute(). Em seguida, crie duas classes de comando concretas:
    • InsertCommand - recebe um Document e uma string text em seu construtor. Quando executado, ele anexa o texto ao documento e imprime Inserted: {text}
    • DeleteCommand - recebe um Document e um int count em seu construtor. Quando executado, ele remove os últimos count caracteres do documento e imprime Deleted: {count} characters
  • Document.cs: Crie uma classe Document no mesmo namespace. Este é o seu receptor (receiver) - o objeto que realmente realiza as operações de texto. Ele deve ter:
    • Um campo de string privado para armazenar o conteúdo (inicialize como uma string vazia)
    • Um método Append(string text) que adiciona texto ao conteúdo
    • Um método RemoveLast(int count) que remove os últimos count caracteres (se o count exceder o comprimento do conteúdo, limpe todo o conteúdo)
    • Um método GetContent() que retorna o conteúdo atual
  • Program.cs: Crie uma classe Editor que atua como o invocador (invoker). Ela deve ter um método SetCommand(ICommand command) e um método ExecuteCommand() que executa o comando atual. No seu código principal, demonstre o padrão command processando uma série de operações de edição.

Você receberá as seguintes entradas:

  • Número de comandos a serem executados
  • Para cada comando: o tipo de comando (insert ou delete) seguido pelo texto a ser inserido ou pelo número de caracteres a serem excluídos

Após executar todos os comandos, imprima o conteúdo final do documento em uma nova linha com o formato Content: {content}.

Por exemplo, se as entradas forem:

4
insert
Hello
insert
 World
delete
3
insert
!

A saída deve ser:

Inserted: Hello
Inserted:  World
Deleted: 3 characters
Inserted: !
Content: Hello Wo!

Observe como o Editor (invocador) não sabe nada sobre manipulação de texto - ele simplesmente executa qualquer comando que lhe seja dado. Os comandos encapsulam tanto a ação quanto o receptor, facilitando a adição de novas operações como ReplaceCommand sem alterar o editor!

Folha de consulta

O padrão Command é um padrão comportamental que encapsula uma solicitação como um objeto independente contendo todas as informações sobre a solicitação. Isso permite que você passe solicitações como argumentos de método, as coloque em fila, registre-as ou suporte operações que podem ser desfeitas.

O padrão possui quatro componentes principais:

  • Interface Command - define o método Execute()
  • Comandos concretos - implementam a interface de comando e encapsulam ações específicas
  • Receiver (Receptor) - o objeto que realiza o trabalho real
  • Invoker (Invocador) - o objeto que aciona os comandos sem conhecer sua implementação

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

Receiver

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

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

O padrão Command é útil para implementar a funcionalidade de desfazer, gravação de macros ou enfileiramento de operações para execução posterior. Cada comando encapsula tudo o que é necessário para realizar uma ação, tornando os sistemas mais flexíveis e extensíveis.

Experimente você mesmo

using System;
using TextEditor;

// TODO: Crie a classe Editor (o invoker)
public class Editor
{
    // TODO: Adicione um campo privado para armazenar o comando atual
    private ICommand _command;

    // TODO: Implemente o método SetCommand
    public void SetCommand(ICommand command)
    {
        // TODO: Armazene o comando
    }

    // TODO: Implemente o método ExecuteCommand
    public void ExecuteCommand()
    {
        // TODO: Execute o comando atual
    }
}

class Program
{
    public static void Main(string[] args)
    {
        // Leia o número de comandos
        int n = Convert.ToInt32(Console.ReadLine());

        // Crie o documento (receiver)
        Document document = new Document();

        // Crie o editor (invoker)
        Editor editor = new Editor();

        // TODO: Processe cada comando
        for (int i = 0; i < n; i++)
        {
            string commandType = Console.ReadLine();

            // TODO: Com base no commandType, crie o comando apropriado
            // - Se for "insert": leia o texto e crie o InsertCommand
            // - Se for "delete": leia a contagem e crie o DeleteCommand
            // Em seguida, defina o comando no editor e execute-o
        }

        // TODO: Imprima o conteúdo final com o formato "Content: {content}"
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos