Você já se deparou com uma unit de negócio onde o comportamento de um método é governado por um emaranhado de if FStatus = stPendente then... else if FStatus = stPago then...? Ou talvez tenha tido dificuldade em implementar um sistema de “Desfazer” (Undo) ou uma fila de processamento assíncrono?
Neste artigo, veremos como o padrão State limpa a lógica de estados finitos e como o Command transforma métodos em cidadãos de primeira classe no Delphi 13.
1. State: Objetos com Crise de Identidade (Positiva)
No desenvolvimento de sistemas corporativos, é comum encontrarmos entidades cujo comportamento é ditado por um “status” (Ex: Pedido Aberto, Faturado, Cancelado, Devolvido). O erro clássico é tentar gerenciar as regras de transição e permissões usando blocos massivos de if-then-else ou case dentro da classe de negócio.
O Problema: A Fragilidade dos Estados Mutáveis
Quando a lógica de estado está espalhada, o código torna-se frágil.
- Cenário de Risco: Você permite que um pedido seja cancelado, mas esquece de verificar se ele já foi faturado em um dos dez pontos de validação.
- Impacto no Delphi 13: Adicionar um novo estado (como “Em Separação”) exige que você vasculhe toda a Unit em busca de condicionais de status, aumentando drasticamente o risco de bugs de regressão e violando o Princípio Aberto/Fechado (OCP).
A Solução: O Objeto como seu Próprio Comportamento
O padrão State propõe que cada estado seja uma classe independente que implementa uma interface comum (ex: IPedidoEstado). O objeto principal (Contexto) apenas delega as ações para a instância do estado atual.
Por que isso revoluciona sua arquitetura no Delphi 13?
- Eliminação de Condicionais: O “cérebro” do objeto é movido para classes menores. Se o estado atual é
TEstadoFaturado, o métodoCancelarsimplesmente lança uma exceção ou executa a lógica de estorno específica, sem precisar de um únicoif. - Transições Seguras: A lógica de qual estado vem depois de qual fica encapsulada. O estado
TAbertosabe que pode evoluir paraTPago, mas não paraEntregue. - Modularidade Sênior: Você ganha a capacidade de adicionar novos estados criando apenas uma nova Unit e classe, sem tocar no código core da classe de Pedido.
No Delphi 13, a transição entre estados torna-se fluida e atômica. Ao mudar a instância de estado, o objeto altera seu vocabulário de comportamentos instantaneamente, garantindo que a regra de negócio seja respeitada por design, e não por verificações manuais exaustivas.
2. Command: Transformando Ações em Objetos
O padrão Command encapsula uma solicitação como um objeto, permitindo parametrizar clientes com diferentes solicitações, enfileirar ou registrar log de solicitações e suportar operações que podem ser desfeitas.
Implementação Técnica: Desacoplando o “Quem pede” do “Quem faz”
No Delphi 13, o Command é a base para sistemas que precisam de filas de execução ou botões que compartilham a mesma lógica sem estar presos à UI.
unit Regys.Patterns.Command;
interface
type
// 1. A Interface do Comando
ICommand = interface
['{C1D2E3B4-A5F6-4789-B0C1-D2E3F4A5B6C7}']
procedure Execute;
procedure Undo;
end;
// 2. O Receiver (Quem realmente sabe fazer o trabalho)
TLuz = class
public
procedure Ligar;
procedure Desligar;
end;
// 3. O Comando Concreto
TLigarLuzCommand = class(TInterfacedObject, ICommand)
private
FLuz: TLuz;
public
constructor Create(ALuz: TLuz);
procedure Execute;
procedure Undo;
end;
implementation
{ TLigarLuzCommand }
constructor TLigarLuzCommand.Create(ALuz: TLuz);
begin
FLuz := ALuz;
end;
procedure TLigarLuzCommand.Execute;
begin
FLuz.Ligar;
end;
procedure TLigarLuzCommand.Undo;
begin
FLuz.Desligar;
end;
end.
3. Aplicação no Dia a Dia: Workflows e Sistemas de Undo/Redo
No quotidiano de um arquiteto Delphi 13, a aplicação conjunta de State e Command permite construir sistemas que não apenas “funcionam”, mas que são capazes de gerenciar processos de longa duração e interações ricas com o utilizador.
A. State: Gerenciando o Ciclo de Vida de Documentos Fiscais
Um dos cenários mais complexos em ERPs brasileiros é o fluxo de uma NF-e ou CT-e. O documento passa por estados como: Em Digitação, Validada, Transmitida, Autorizada, Cancelada ou Encerrada.
- Uso Prático: Cada estado define o que pode acontecer a seguir. No estado
Autorizada, o métodoEditardo State lança uma exceção, enquanto o métodoImprimirexecuta a geração do DANFe. - Vantagem: Você centraliza as regras de negócio fiscais dentro dos estados correspondentes. A sua classe
TNotaFiscalfica limpa, delegando a inteligência para os objetos de estado, o que facilita enormemente a manutenção quando a legislação impõe novas regras de transição.
B. Command: Sistemas de Undo/Redo e Transações de UI
A implementação de “Desfazer” (Undo) é um diferencial de qualidade em qualquer software. Com o Command, cada ação do utilizador (editar um campo, apagar um registo) é encapsulada.
- Implementação no Delphi 13: Você mantém uma
TStack<ICommand>chamada UndoStack. Quando o utilizador clica em “Desfazer”, você retira o último comando e chama o métodoUndo. - Cenário Real: Em editores de layout ou cadastros complexos, isso evita que o utilizador perca trabalho e permite que o sistema reverta estados do banco de dados ou da memória de forma atômica e segura.
C. Command para Processamento Assíncrono e Filas (Background Tasks)
Com a necessidade de manter a UI sempre responsiva no Delphi 13, tarefas pesadas (como gerar um PDF de 500 páginas ou enviar um lote de e-mails) não podem travar a aplicação.
- A Transição: Em vez de chamar o método pesado diretamente no botão, você cria um objeto
TExportCommande o coloca numaTThreadedQueue<ICommand>. - Vantagem: Uma ou mais threads de background (trabalhando com
TTask) consomem esta fila. O padrão Command garante que todos os parâmetros necessários para a execução foram capturados no momento em que o utilizador clicou no botão, evitando erros de concorrência.
D. Automação de Testes e Macros
Ao utilizar o Command, você ganha a capacidade de “gravar” sequências de ações. Isso é extremamente útil para criar testes de integração automatizados: você pode disparar uma lista de comandos pré-configurados e verificar o estado final do sistema, garantindo que o workflow definido pelo padrão State foi respeitado integralmente.
4. Nuances Técnicas: Memória e Transição de Estados no Delphi 13
A implementação dos padrões State e Command no Delphi 13 exige um olhar atento para o ciclo de vida dos objetos. Como ambos lidam com a criação constante de instâncias (novos estados ou novos comandos), a gestão eficiente de recursos é o que separa um protótipo de um sistema de missão crítica.
A. Gestão de Memória com Interfaces e ARC
Tanto no State quanto no Command, o uso de Interfaces (IInterface) é a prática recomendada.
- No State: Quando o contexto altera o estado atual (
FEstado := TEstadoNovo.Create(Self)), a contagem de referência do estado antigo cai para zero, disparando a destruição automática. Isso evita o gerenciamento manual complexo deFreedentro de métodos de transição. - No Command: Ao usar uma
TStack<ICommand>para Undo, os comandos permanecem na memória. Sem interfaces, você teria que percorrer a pilha manualmente para liberar cada objeto. Com interfaces, basta limpar a lista (FStack.Clear) e o Delphi cuidou do restante.
B. Transição de Estados: Quem manda em quem?
Uma dúvida comum no Delphi 13 é: “Onde deve residir a lógica de troca de estado?”.
- No Contexto: Mais simples, mas torna o contexto pesado.
- Nos Estados (Recomendado): Cada estado concreto conhece o seu sucessor. Ao finalizar sua lógica, o estado chama um método no contexto para injetar a próxima instância.
- Dica Técnica: No Delphi 13, passe o contexto como uma referência
[Weak]para o estado, ou use uma interface para evitar referências circulares que impediriam a liberação da memória.
C. Command e o Desafio da Thread-Safety
Ao usar o Command para processamento em background (via TTask ou TThreadedQueue), você deve garantir que o comando seja imutável após sua criação.
- O Perigo: Se um comando acessa um componente da UI (como um
TEdit.Text) diretamente de uma thread secundária, o sistema irá travar. - A Solução: Capture todos os valores necessários no Constructor do comando. No método
Execute, trabalhe apenas com essas variáveis locais. Se precisar atualizar a UI ao final, useTThread.Queuepara despachar o resultado de volta à Main Thread.
D. Overhead de Instanciação vs. Flyweight
Se o seu sistema alterna estados milhares de vezes por segundo, criar um novo objeto a cada transição pode sobrecarregar o Memory Manager.
- Otimização: Em casos de alta performance, você pode combinar o State com o padrão Flyweight, mantendo instâncias estáticas dos estados e apenas trocando a referência no contexto, eliminando o custo de
AllocMemeFreeMem.
E. Resumo
- Gestão de Memória com Interfaces: Tanto no State quanto no Command, o uso de Interfaces no Delphi 13 facilita a vida. No State, quando o Contexto troca de
FEstadoAtual := TEstadoNovo.Create(Self), a contagem de referência limpa o estado antigo automaticamente. - Transição de Estados: Uma dúvida comum é: “Quem deve trocar o estado?”. No Delphi 13, preferimos que os próprios Estados Concretos decidam para qual estado o Contexto deve ir, passando o Contexto no construtor do Estado.
- Command e Anonymous Methods: Para comandos muito simples, você pode usar métodos anônimos (
TProc). No entanto, para sistemas que exigem Undo, a abordagem baseada em classes e interfaces vista acima é superior por permitir o armazenamento de estados anteriores.
Referências
FLICK, Stefan. Design Patterns with Delphi: Build enterprise-grade applications with modern Delphi and the right design patterns. 1. ed. Birmingham: Packt Publishing, 2024.
GAMMA, Erich; HELM, Richard; JOHNSON, Ralph; VLISSIDES, John. Padrões de Projeto: Soluções reutilizáveis de software orientado a objetos. 1. ed. Porto Alegre: Bookman, 2000.
NOGUEIRA, Rodrigo. Delphi e Clean Architecture: Princípios e práticas para software escalável. 2. ed. São Paulo: Editora Engenharia de Software, 2025.
TEIXEIRA, Marcello. Delphi High Performance: Build fast Delphi applications using concurrency, parallel programming and memory management. 1. ed. Birmingham: Packt Publishing, 2018.
Descubra mais sobre Régys Borges da Silveira
Assine para receber nossas notícias mais recentes por e-mail.
Dê-nos sua opinião, seu comentário ajuda o site a crescer e melhorar a qualidade dos artigos.