Extrair uma decisão de negócio e identificar onde a persistência deve ser coordenada
Tutorial · prática orientada · IntermediárioUnits, funções e contratos de entrada e saída
Unit principal compilada e exercitada com DCC32 37.0, build 37.0.59082.6021. Referência editorial: Delphi 11.3 e 13.2; essas duas versões não foram verificadas individualmente.Documentação, instalação e limites de Fundamentos em seis units
O pedido do usuário é simples: adicionar itens a uma lista. O evento da tela lê um campo, verifica um limite, salva no banco e mostra o resultado. Tudo funciona até a mesma regra precisar atender uma importação ou uma API.
Separar responsabilidades começa por localizar as decisões. Não é preciso criar uma arquitetura extensa para reconhecer o que é apresentação e o que deve continuar igual sem aquela tela.
Defina a política sem nomes de componentes
Neste exercício, uma lista possui uma quantidade atual e um limite máximo. Uma adição é aceita se todas as quantidades forem válidas e houver espaço. Quantidade a adicionar deve ser positiva; quantidade atual e limite não podem ser negativos.
Essa é uma política didática de contagem, não uma regra real de estoque. Uma aplicação comercial pode exigir reserva, disponibilidade e autorização adicionais.
Coloque a decisão em uma unit independente
Crie Lista.Politica.pas:
unit Lista.Politica;
interface
function PodeAdicionar(const Atual, Quantidade,
Limite: Integer): Boolean;
implementation
uses
System.SysUtils;
function PodeAdicionar(const Atual, Quantidade,
Limite: Integer): Boolean;
begin
if (Atual < 0) or (Quantidade <= 0) or (Limite < 0) then
raise EArgumentException.Create('Contagem inválida');
if Atual > Limite then
Exit(False);
Result := Quantidade <= Limite - Atual;
end;
end.A comparação usa a diferença disponível em vez de somar duas entradas antes de verificar o limite. Isso evita um overflow da soma nesse contrato, já que a subtração acontece após confirmar valores não negativos e Atual <= Limite.
O retorno False significa que não cabe. Uma entrada fora do contrato gera exceção. Esses caminhos precisam ser documentados para que a apresentação não confunda falta de espaço com um defeito na entrada.
A tela traduz; a regra decide
A apresentação converte o texto digitado, aponta o campo inválido e mostra a mensagem. Ela não deve copiar a fórmula para decidir antes de chamar a unit e depois esquecer de chamar a regra no caminho de gravação.
Uma validação visual pode antecipar feedback. A decisão confiável ainda precisa ocorrer no ponto em que a operação é aplicada. Num sistema web, não confie em um valor de quantidade atual informado pelo navegador.
O caso de uso coordena uma operação
Se adicionar itens altera uma base de dados, alguém deve obter a contagem atual, verificar autorização, aplicar a política e persistir de forma consistente. Esse trabalho de coordenação pode pertencer a um serviço de aplicação ou caso de uso.
Apresentação → Caso de uso → Política
↓
Persistência autorizada e consistenteA política não abre uma conexão nem escolhe uma mensagem de botão. O serviço não precisa conhecer TEdit ou o formulário principal. A infraestrutura implementa os detalhes de acesso ao banco.
Se duas operações leem a mesma contagem simultaneamente, ambas podem concluir que há espaço. A regra pura não elimina essa corrida. Use uma transação e um mecanismo de controle de concorrência adequado ao banco e ao contrato da operação.
Teste a decisão por exemplos
| Atual | Adicionar | Limite | Expectativa |
|---|---|---|---|
| 2 | 3 | 5 | Aceita |
| 2 | 4 | 5 | Rejeita por capacidade |
| 5 | 1 | 5 | Rejeita por capacidade |
| 0 | 1 | 0 | Rejeita por capacidade |
| 2 | 0 | 5 | Entrada inválida |
| -1 | 1 | 5 | Entrada inválida |
Esses casos foram executados no projeto de verificações; confira o relatório incluído no download. Verifique também contagens próximas de High(Integer).
Quando a separação está ajudando
Uma boa fronteira permite alterar a mensagem sem mudar a política e usar a mesma política numa operação sem tela. Uma separação ruim exige atravessar vários arquivos que apenas repassam chamadas sem explicar nenhuma responsabilidade.
As estruturas de units e interfaces usadas aqui seguem os mecanismos da linguagem descritos no guia oficial Delphi. A escolha das fronteiras é uma proposta de desenho, não uma imposição da linguagem.
Como exercício, substitua o limite fixo por uma política recebida pelo caso de uso e descreva quem tem permissão para alterá-la. Continue em Interfaces na prática para decidir quando um contrato de dependência é útil.
Desafio: capacidade, sem trocar a regra
- PodeAdicionar(2,3,5): True, capacidade exata.
- PodeAdicionar(2,4,5): False, excede limite.
- Quantidade zero ou atual negativo: EArgumentException.
- Valores próximos de High(Integer): evitar overflow.
Entrada → conversão → caso de uso → política → coordenação da persistência → saída. A função pura não impede duas gravações concorrentes. Autorização, transação e conflito pertencem à coordenação; banco e ensaio de persistência ficam adiados por decisão do responsável. Fonte e testes.
Sua regra continuaria funcionando se a tela fosse substituída por uma API?
Teste capacidade exata (2,3,5), capacidade excedida (2,4,5), quantidade zero e valores próximos de High(Integer). Separe política de capacidade da mensagem visual.
Ver uma pista para começar
A regra decide capacidade. A interface converte entradas. Concorrência e persistência precisam de coordenação própria.
Não precisa acertar de primeira. Observe o resultado e explique o que mudou.

