CS Coder
Delphi

Units no Delphi: organize responsabilidades antes de organizar pastas

Entenda interface, implementation e dependências usando uma regra de validação que pode ser chamada por VCL, FireMonkey ou uma API.

· 4 min de leitura
Objetivo e formato

Extrair uma validação da tela e reconhecer a direção das dependências

Tutorial · prática orientada · Fundamentos
Antes de experimentar

Saber criar um projeto e adicionar uma unit

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

Quando uma aplicação cresce, é comum criar pastas como Forms, Utils e Services. Isso ajuda a localizar arquivos, mas não garante que o código esteja organizado: um formulário ainda pode conter validação, SQL e integração HTTP no mesmo evento.

Uma unit é uma fronteira de código. O primeiro trabalho é decidir o que ela oferece e quais detalhes deve esconder. Neste tutorial, vamos extrair a validação de um nome, sem depender de componentes visuais.

Interface e implementation têm papéis diferentes

A seção interface declara o que outras units podem utilizar. A seção implementation contém a implementação e pode manter auxiliares que não fazem parte do contrato público. A declaração de uma função e seu corpo não são duas funções distintas. A documentação apresenta essa estrutura no guia da linguagem Delphi.

Pense em um formulário que precisa conferir um nome antes de salvar. Expor uma função pequena permite que qualquer interface use a mesma regra. Não é necessário expor um formulário para validar uma string.

Extraia uma unit pequena

Crie Cadastro.Nomes.pas com este conteúdo. A regra adotada é didática: exige algum texto após remover espaços nas extremidades. Não pretende validar todos os nomes pessoais possíveis.

delphi
unit Cadastro.Nomes;

interface

function NomePreenchido(const Nome: string): Boolean;

implementation

uses
  System.SysUtils;

function NomePreenchido(const Nome: string): Boolean;
begin
  Result := Trim(Nome) <> '';
end;

end.

System.SysUtils fica na implementação porque nenhum tipo público desse exemplo exige a unit. Quem chama NomePreenchido precisa conhecer seu parâmetro e seu retorno, não a função usada internamente.

No formulário, adicione Cadastro.Nomes ao uses e chame NomePreenchido(EditNome.Text). A tela continua responsável por obter o texto, apresentar a mensagem e posicionar o foco. A regra não precisa conhecer essas decisões.

A direção da dependência importa

O formulário pode depender de Cadastro.Nomes. A unit de nomes não deve passar a depender do formulário apenas para mostrar uma mensagem. Essa segunda dependência criaria um caminho de volta à apresentação e dificultaria reutilizar a validação.

Um teste mental útil é substituir a tela por um comando de console. A regra ainda funciona? Nesse exemplo, sim. Se a unit precisa de EditNome, ShowMessage ou do formulário principal, a fronteira ficou incompleta.

Evite usar uma unit Utils como destino de todo código extraído. Uma coleção de funções sem relação fica difícil de descobrir e revisar. Prefira nomes que revelem a responsabilidade: validação de nomes, cálculo de frete ou leitura de configuração.

Experimente sem abrir uma tela

Em um projeto de console, inclua a unit e execute as chamadas abaixo no bloco principal:

delphi
Writeln(NomePreenchido('Ana'));    // esperado: TRUE
Writeln(NomePreenchido('   '));    // esperado: FALSE
Writeln(NomePreenchido(' Ana '));  // esperado: TRUE

Confira também uma string vazia. As quatro entradas de nomes foram executadas no projeto de verificações e produziram o comportamento esperado. A unit completa foi compilada e exercitada no projeto de verificações disponível abaixo.

Quando não vale extrair

Nem toda linha de um evento precisa virar uma classe ou uma unit. Alterar a legenda de um botão em resposta a um clique é apresentação. Extraia quando existir uma responsabilidade que precise ser compreendida, reutilizada ou testada separadamente.

A estrutura também não precisa começar com quatro camadas e dezenas de arquivos. Comece com uma fronteira útil e observe se as próximas alterações ficam mais simples de localizar.

Desafio e próxima leitura

Acrescente uma segunda função que imponha um limite de tamanho definido por um contrato de cadastro. Decida se esse limite deve contar unidades UTF-16 ou caracteres percebidos pelo usuário antes de implementar; Length de uma string Delphi não resolve todas as questões de Unicode.

Depois, avance para Interfaces na prática para separar uma necessidade da forma de implementá-la.

Extração: antes, depois e contrato Unicode

Antes: evento decide validade e mensagem. Depois: Cadastro.Nomes decide NomePreenchido; a tela traduz o resultado.

  1. Liste entrada string e saída Boolean; não passe TEdit ao domínio.
  2. Extraia a função e crie console com nome, vazio e espaços.
  3. Mantenha mensagem na tela e remova dependências UI da unit.
  4. Compare console e tela chamando a mesma regra.

Árvore: Projeto.dpr → Cadastro.Nomes.pas; Formulario.pas → Cadastro.Nomes.pas. A dependência não volta para a tela.

Trim não define todas as categorias Unicode de espaço. Antes de ampliar NomePreenchido, declare política para tabulação, quebra de linha, espaço não separável e caracteres combinantes. Não mude contrato sem casos novos.

Abrir projeto de exemplo ↗