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 contendo todas as informações sobre a solicitação. Essa transformação permite passar solicitações como argumentos de métodos, enfileirá-las, registrá-las ou oferecer 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 de fato) e um invocador (o objeto que aciona 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 invocador armazena e executa comandos sem saber o que eles fazem:
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(); // Luz está LIGADA
remote.SetCommand(new TurnOffCommand(light));
remote.PressButton(); // Luz está DESLIGADAO padrão Command é particularmente poderoso para implementar a funcionalidade de desfazer, a gravação de macros ou o 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 criar um sistema de comandos para um editor de texto usando o padrão Command. Você criará um sistema no qual 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, acrescenta o texto ao documento e imprimeInserted: {text}DeleteCommand- recebe umDocumente umint countem seu construtor. Quando executado, remove os últimoscountcaracteres do documento e imprimeDeleted: {count} characters
Document.cs: Crie uma classeDocumentno mesmo namespace. Este é o receptor — o objeto que realmente executa as operações de texto. Ele deve ter:- Um campo privado do tipo string para armazenar o conteúdo (inicializado 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 count exceder o comprimento do conteúdo, limpa todo o conteúdo) - Um método
GetContent()que retorna o conteúdo atual
Program.cs: Crie uma classeEditorque atua como o invocador. 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 executar
- Para cada comando: o tipo de comando (
insertoudelete), seguido pelo texto a inserir ou pelo número de caracteres a excluir
Depois de 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 deverá ser:
Inserted: Hello
Inserted: World
Deleted: 3 characters
Inserted: !
Content: Hello Wo!Observe como o Editor (invocador) não sabe nada sobre a manipulação de texto — ele simplesmente executa qualquer comando que receba. Os comandos encapsulam tanto a ação quanto o receptor, facilitando a adição de novas operações, como ReplaceCommand, sem alterar o editor!
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étodosPratique por conta própria: Compilador de C# online