Class Helper – Adicionando uma nova variável, você já tentou ?

Por algum tempo fiquei pensando em uma solução para Class Helper ganhar poder de adicionar uma nova variável. Confesso que já estava desistindo, parecia não ser possível… mas – pensando bem….

Digamos que você tenha uma classe base que gostaria de fazer um Class Helper dela:

Exemplo de uma classe original:
[code]

TComponentX = class(TComponent)
public
published
end;

[/code]
(Code:A)

O desafio é como incluir uma nova variável a classe TComponentX utilizando de Class Helper…

Razões para usar um "Class Helper" e não uma herança: 
    se houver possibilidade de injetar a variável através de herança, 
    é provável que não irá precisar criar um "Class Helper" 
    - as razões para criar um "Class Helper" 
    é dispensar mudanças nos objetos em units já implementadas.

Agora, vamos usar o “Class Helper” para injetar uma nova variável à classe TComponentX:
[code]
TComponentHelper = Class Helper TComponent
public
Ligado:Boolean;
end;
[/code]
(Code:B)

Se estiver habituado ao uso de Class Helper, já deve ter notado que este exemplo (Code:B) não é compilado no Delphi – reclamando que um “Class Helper” não pode inserir uma nova variável. Não seja apressado, já lembrou que existe um “Class Var” e logo sugere escrever assim: ” class var Ligado:Boolean; “… Se este for o seu caso, não tenho boa notícia – você terá criado uma única referência para a variável, não podendo receber valores diferentes nas várias instâncias que a aplicação desejar manter carregada na memória – ou seja, criou uma simples variável GLOBAL que é compartilhada com todas as instâncias da classe;

No nosso caso, queremos que cada instância tenha o seu próprio valor, portanto não pode utilizar um “Class Var” como solução.

PROPOSTA:
[code]
unit Unit1;

interface

uses System.Classes, System.Generics.Collections;

type

TComponentHelper = Class Helper for TComponent
protected
function GetLigado: boolean;
procedure SetLigado(const AValue: boolean);
public
property Ligado: boolean Read GetLigado write SetLigado;
end;

implementation

var
LComponentLigado: TDictionary<TComponent, boolean>;

function TComponentHelper.GetLigado: boolean;
begin
result := true; // responde um padrão, para quando não existir;
if LComponentLigado.ContainsKey(self) then
result := LComponentLigado.Items[self]; // pega o valor da lista
end;

procedure TComponentHelper.SetLigado(const AValue: boolean);
begin
LComponentLigado.AddOrSetValue(self, AValue); // inclui na lista
end;

initialization

LComponentLigado := TDictionary<TComponent, boolean>.Create;

finalization

LComponentLigado.free;

end.
[/code]

A implementação permite adicionar novas variáveis ao objeto do “Class Helper” sem interferir no funcionamento da classe padrão.

3 comentários

  1. Muito bem colocado Amarildo.
    Quando saiu essa feature no delphi eu imaginei um mundo maravilhoso, até me deparar com essa limitação, que depois de muitas tentativas de várias formas, todas frustradas, cheguei finalmente nesse recurso, e tenho usado desde então com sucesso.
    Isso fica como dica para quem está querendo o mesmo objetivo, usar como “atalho”.
    Parabéns !!

  2. Muito bom! Parabéns pela dica… são esses tipos de situações que facilitam nossas vidas de programador. E programadores dispostos a compartilhar conhecimento.

  3. Na verdade esta implementação esta incompleta..
    Primeiro é necessário retirar do dicionário global os itens adicionados ao mesmo.
    Segundo para que se este modelo seja utilizado em um aplicativo multi-thread é necessário adicionar os controles de acesso.
    Mas no geral é uma boa saída para algo bem específico, não seria uma boa ideia o uso generalizado deste modelo em um sistema..

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *