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á DESLIGADAO 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.
Desafio
FácilVamos 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 interfaceICommandno namespaceTextEditorcom um único métodoExecute(). Em seguida, crie duas classes de comando concretas:InsertCommand- recebe umDocumente uma stringtextem seu construtor. Quando executado, ele anexa o texto ao documento e imprimeInserted: {text}DeleteCommand- recebe umDocumente umint countem seu construtor. Quando executado, ele remove os últimoscountcaracteres do documento e imprimeDeleted: {count} characters
Document.cs: Crie uma classeDocumentno 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 últimoscountcaracteres (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 classeEditorque atua como o invocador (invoker). Ela deve ter um métodoSetCommand(ICommand command)e um métodoExecuteCommand()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 (
insertoudelete) 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 OFFO 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}"
}
}
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
1Fundamentos de POO
Arquivos ExternosNamespaces e DiretivasIntrodução a Classes e ObjetosA Palavra-chave 'this'Métodos e ParâmetrosCampos vs PropriedadesConstrutoresInicializadores de ObjetosRecapitulação - Calculadora Simples4Herança
Sintaxe Básica de Herança (:)A Palavra-chave 'base'Palavras-chave Virtual e OverrideClasses SeladasA Classe Base 'object'Recapitulação - Hierarquia de Funcionários7Recursos Avançados
Sobrecarga de OperadoresIndexadores (this[])Sobrescrita de ToString()Métodos de ExtensãoRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoSingleton Thread-SafePadrão FactoryPadrão Observer (Eventos)Padrão Strategy2Propriedades e Membros Estáticos
Propriedades AutoimplementadasPropriedades de Apenas Leitura/EscritaCampos e Métodos EstáticosClasses EstáticasMembros com Corpo de Expressão5Polimorfismo e Interfaces
Polimorfismo: Compilação vs ExecuçãoInterface vs Classe AbstrataMúltiplas InterfacesInterfaces ExplícitasUpcasting e DowncastingRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição sobre HerançaGenerics (Classes e Métodos)Delegates e EventosAtributos e ReflectionIDisposable e a Instrução usingFundamentos de Injeção de Dependência11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Arquitetura de Classes
Dados de Instância vs EstáticosPalavras-chave 'readonly' e 'const'Campos de SuporteRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Modificadores de AcessoPropriedades para EncapsulamentoImplementação de Ocultação de DadosPadrões de ImutabilidadeRecapitulação - Registros de Estudantes9Argumentos Variáveis
A Palavra-chave 'params'Parâmetros OpcionaisArgumentos NomeadosSobrecarga de Métodos