GoF, p. 233 também chamado de Action, Transaction
Comando
Command
Transforme uma requisição em objeto — e ganhe fila, log, undo e agendamento de graça.
Encapsular uma solicitação como um objeto, permitindo parametrizar clientes com diferentes solicitações, enfileirar ou registrar solicitações, e suportar operações que podem ser desfeitas.
O pedido no restaurante
Você não vai até o fogão explicar ao cozinheiro o que quer. Você fala com o garçom, que escreve o pedido num papel. O papel vira um objeto independente: pode ser colocado numa fila, passado a outro cozinheiro, arquivado como histórico, ou cancelado. O garçom não sabe cozinhar; o cozinheiro não sabe quem pediu.
A camada de interface precisa disparar operações da camada de negócio. Se cada botão chamar diretamente o método certo, a UI vira um emaranhado de subclasses e conhece detalhes do domínio. Pior: não há como desfazer, repetir, enfileirar ou registrar essas ações.
Extraia a requisição para um objeto com um método `executar()` (e, opcionalmente, `desfazer()`). O invocador só conhece a interface Command. Como o comando é um objeto, você pode guardá-lo numa lista, numa fila ou numa pilha de histórico.
- Handlers de UI com regra de negócio dentro.
- Impossibilidade de implementar Ctrl+Z sem reescrever tudo.
Estrutura
- Command
- Interface com `executar()` e, se houver undo, `desfazer()`.
- ConcreteCommand
- Liga um receptor a uma ação e guarda os parâmetros necessários.
- Invoker
- Dispara o comando; não sabe o que ele faz (botão, menu, fila, atalho).
- Receiver
- Contém a lógica de negócio de verdade.
- Client
- Cria os comandos concretos e os associa aos invocadores.
Implementação
// ── Receiver: onde mora a lógica de verdade ───────────
class Editor { texto = ''; }
// ── Command: contrato com undo ────────────────────────
class Comando {
executar() { throw new Error('abstrato'); }
desfazer() { throw new Error('abstrato'); }
}
class Inserir extends Comando {
constructor(editor, trecho) { super(); this.editor = editor; this.trecho = trecho; }
executar() { this.editor.texto += this.trecho; }
// Cada comando guarda o que precisa para reverter a si mesmo.
desfazer() { this.editor.texto = this.editor.texto.slice(0, -this.trecho.length); }
}
class Maiusculas extends Comando {
constructor(editor) { super(); this.editor = editor; }
executar() { this.anterior = this.editor.texto; this.editor.texto = this.editor.texto.toUpperCase(); }
desfazer() { this.editor.texto = this.anterior; } // memento embutido
}
// ── Invoker: gerencia histórico, ignora o que os comandos fazem ──
class Historico {
#feitos = []; #desfeitos = [];
executar(comando) { comando.executar(); this.#feitos.push(comando); this.#desfeitos = []; }
desfazer() { const c = this.#feitos.pop(); if (c) { c.desfazer(); this.#desfeitos.push(c); } }
refazer() { const c = this.#desfeitos.pop(); if (c) { c.executar(); this.#feitos.push(c); } }
}
const editor = new Editor();
const h = new Historico();
h.executar(new Inserir(editor, 'olá '));
h.executar(new Inserir(editor, 'mundo'));
h.executar(new Maiusculas(editor));
console.log(editor.texto); // OLÁ MUNDO
h.desfazer(); console.log(editor.texto); // olá mundo
h.desfazer(); console.log(editor.texto); // olá
h.refazer(); console.log(editor.texto); // olá mundo - java.lang.Runnable e todo o java.util.concurrent
- javax.swing.Action
- Actions do Redux; jobs de filas como Sidekiq/Celery/BullMQ
- Event sourcing e CQRS têm o Command na raiz
Consequências
- Desacopla quem invoca de quem executa.
- Habilita desfazer/refazer, filas, agendamento, log e retry — tudo porque a ação virou objeto.
- Permite compor macro-comandos (um Composite de comandos).
- Novos comandos entram sem alterar os existentes (Aberto/Fechado).
- Uma classe por operação — pode gerar muitas classes pequenas.
- Camada extra entre remetente e receptor.
- Você precisa de desfazer/refazer.
- Operações devem ser enfileiradas, agendadas ou executadas remotamente.
- Você quer parametrizar objetos com ações (botões, menus, atalhos, jobs).
- Você quer um log de operações para auditoria ou recuperação.
- A ação é simples, única e não precisa de histórico — uma função basta.
Relações com outros padrões
- Memento
- Memento guarda o estado que o Command precisa para desfazer operações complexas.
- Chain of Responsibility
- Comandos podem ser passados por uma cadeia de handlers.
- Composite
- Macro-comandos são Composites de Commands.
- Prototype
- Comandos guardados em histórico são frequentemente clonados.
- Strategy
- Strategy parametriza um objeto com um ALGORITMO; Command, com uma AÇÃO a executar depois.
Verificação
O que torna possível implementar “desfazer” com o padrão Command?
- A ação vira um objeto que pode guardar seu próprio estado anterior e ser empilhado num histórico
- O padrão exige que todas as operações sejam matematicamente inversíveis
- O invocador mantém uma cópia completa do sistema a cada passo
- O receptor implementa automaticamente um método undo
Reificar a requisição é o truque central: um objeto pode ser guardado, listado, serializado, enfileirado e revertido — coisas que uma chamada de método não permite.