Pular para o conteúdo
GoF Padrões de Projeto Comportamentais
Comportamental escopo de objeto
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.

Complexidade média Frequência de uso muito comum
Intençãocomo o livro define

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.

Analogiauma imagem do mundo real

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.

O problema

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.

A solução

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.

Sintomascomo reconhecer no seu código
  • Handlers de UI com regra de negócio dentro.
  • Impossibilidade de implementar Ctrl+Z sem reescrever tudo.

Estrutura

executar()age sobreClientBotao (Invoker)- comando+ clicar()«interface»Comando+ executar()+ desfazer()ColarComandoCopiarComandoEditor (Receiver)+ inserir(t)
Fig. 14 — Command herda / implementa cria usa / contém
Ver este diagrama sendo desenhado, traço a traço
Participantes
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

Listagem 14 Editor de texto com desfazer/refazer
// ── 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
Na práticaonde ele já existe
  • 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

A favor
  • 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).
Contra
  • Uma classe por operação — pode gerar muitas classes pequenas.
  • Camada extra entre remetente e receptor.
Use quando
  • 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.
Evite quando
  • A ação é simples, única e não precisa de histórico — uma função basta.

Relações com outros padrões

costuma andar junto
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.
parecido / fácil de confundir
Strategy
Strategy parametriza um objeto com um ALGORITMO; Command, com uma AÇÃO a executar depois.

Verificação

Questãoa resposta está marcada

O que torna possível implementar “desfazer” com o padrão Command?

  1. A ação vira um objeto que pode guardar seu próprio estado anterior e ser empilhado num histórico
  2. O padrão exige que todas as operações sejam matematicamente inversíveis
  3. O invocador mantém uma cópia completa do sistema a cada passo
  4. 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.