Class Helpers e Record Helpers

Há algumas semanas, enquanto eu examinava a lista de artigos do blog, notei que até o momento não fiz publicações sobre Helpers no Delphi. No artigo de hoje, discorro brevemente sobre o conceito, vantagens, restrições e exemplos deste recurso que considero fantástico!

Convenhamos: já passou pela sua cabeça incluir um novo comportamento uma classe da RTL ou VCL do Delphi, não é? Algumas vezes, uma simples operação é tão comum no código que seria muito bom se já estivesse presente na classe nativa. Pois bem, pessoal, os Helpers existem para isso!

Afinal, o que são Helpers?

Em poucas palavras, trata-se de uma estrutura que introduz comportamentos ou atributos adicionais à uma classe ou record sem a necessidade de utilizar heranças. Com Helpers, portanto, podemos inserir novas funcionalidades de maneira fácil e usá-las como se fizessem parte da classe que estendemos.

Helpers são divididos em dois tipos: Class Helpers e Record Helpers. O primeiro, como o próprio nome diz, é associado à classes. O segundo permite a extensão de tipos de dados, como string, integer e enumerados.

A sintaxe de ambos segue basicamente o seguinte padrão:

Exemplo de Class Helper

Considere, por exemplo, que seja necessário verificar se o conteúdo de um componente TEdit está vazio. Provavelmente escreveríamos o código a seguir:

Imagine se fosse possível executar a mesma validação apenas com a instrução abaixo:

Bem melhor, não? O código ficaria mais limpo e expressivo.

Porém, sabemos que TEdit é um componente nativo da VCL do Delphi e não podemos simplesmente alterá-lo. Uma alternativa seria criar um componente herdado de TEdit para adicionar essa funcionalidade, mas, para isso, teríamos que criar um pacote para instalá-lo, e depois substituir todos os componentes TEdit na aplicação por este novo componente. Em suma: daria um trabalhão!

Com Class Helpers, podemos adicionar essa funcionalidade sem a necessidade de alterar a definição da classe TEdit. Ao invés disso, criaremos uma “extensão” da classe:

Só isso, pessoal! O próximo passo é declarar a unit que contém esse Helper na seção uses do formulário no qual desejamos utilizá-lo.

Observem, em seguida, que o próprio Code Completion do Delphi já sugere a nossa função, como se ela existisse na própria classe TEdit:

Exemplo de Class Helper para o componente TEdit

Muito bom, hein? 🙂

Vale lembrar que Class Helpers também podem ser aplicados à RTL. Há algumas semanas, por exemplo, criei um pequeno Helper para a classe TStringList para retornar a existência de um valor específico contido na lista.

Exemplo de Record Helper

Os Record Helpers, por sua vez, nos dão a possibilidade de incluir novos comportamentos a tipos de dados. Como exemplo, suponha que a formatação de um número para valor monetário (com cifrão) seja algo bastante comum no software. Ao invés de utilizarmos o FormatFloat em todas as ocorrências no código, podemos criar um Record Helper para o tipo double com a responsabilidade de retornar o valor formatado:

Dessa forma, ao escrever este código…

… recebemos o seguinte resultado:

Exemplo de Record Helper para o tipo double

 

Use com moderação!

O propósito principal dos Helpers é permitir a extensão de estruturas que não podem ser herdadas ou modificadas. Isso significa que, para classes já criadas no projeto, recomenda-se a alteração de sua própria estrutura ao invés da criação de Helpers. Caso contrário, com o passar do tempo, a existência de vários Helpers no projeto pode dificultar a identificação de comportamentos e, por consequência, a manutenção do projeto.

Restrições

Em julho, recebi um comentário interessante de um leitor chamado Eduardo sobre uma restrição de Record Helpers que até então eu desconhecia. Ao referenciar duas units que contém Record Helpers para o mesmo tipo, apenas a última unit é considerada. Por exemplo, considere as referências abaixo:

A unit HelperString1 será ignorada pelo Delphi e apenas a unit HelperString2 entrará em vigor.

Após algumas pesquisas, encontrei uma explicação da própria Embarcadero sobre essa restrição:

Você pode definir e associar múltiplos Helpers para um único tipo. Porém, apenas um deles terá vigência em qualquer local específico do código. O Helper referenciado no escopo mais próximo (o primeiro da direita para a esquerda na seção uses) será aplicado.

Portanto, procure declarar todas as funcionalidades adicionais de uma classe ou record em uma única unit para cada tipo. Ou então, organize as units de tal forma que apenas uma seja referenciada na seção uses de uma classe.

 

Grande abraço, pessoal!


 

André Celestino