Apesar de ter uma ligação tão intrincada com o COM, mostrei no post anterior que o conceito de interfaces em Delphi pode ser usado de forma desvinculada. Mesmo assim, a escolha de introduzir interfaces tendo o COM em mente produziu alguns efeitos colaterais que não podem ser negligenciados durante o projeto e programação de sistemas onde se queira usar esse recurso.
Em primeiro lugar, as interfaces em Delphi tem suas referências controladas através da implementação do IUnknown. Sempre que você atribui o ponteiro de um objeto ou de uma interface a uma variável de interface, o contador de referências é incrementado. Quando a variável de interface sai de escopo, o contador é automaticamente decrementado e quando chega a zero, o objeto original é removido da memória. Isso foge da forma tradicional de se controlar o ciclo de vida de um objeto em programas Win32 já que a implementação do IUnknown funciona como um garbage collector. Isto é, você cria o objeto que implementa uma interface mas é o compilador quem decide o momento em que o destructor será invocado.
No entanto, se o ponteiro do objeto que você criou jamais for atribuído a uma variável do tipo interface, você ainda é responsável por destruir esse objeto! É fácil ver a bagunça que vai virar se o planejamento não for bem feito, com memória sendo perdida ou erros de access violation sendo gerados do nada. Quando usado em conjunto com o COM, entretanto, a estrutura de criação através de CoClasses se encarregará de destruir corretamente o objeto.
Formas para resolver esse impasse podem ser encontradas num artigo publicado no EDN (Embarcadero Developer Network) : Delphi reference counted interfaces.
O segundo ponto com o qual se preocupar é com a necessidade de recuperar um ponteiro para a classe original a partir de um ponteiro da interface. Isto é, você instanciou a classe, atribuiu o ponteiro a uma interface e agora quer recuperar de novo o ponteiro para a classe. No Delphi, variáveis do tipo class são diferentes de variáveis do tipo interface e elas não são intercambiáveis como em outras linguagens de programação menos ligadas ao COM. De fato, uma variável para classe contem o endereço de memória onde estão os dados dessa classe enquanto que a interface é apenas um ponteiro para a tabela virtual de métodos dessa interface. São, portanto, incompatíveis e isso deve fazer parte do planejamento da hierarquia de classes e interfaces.
Por fim, as interfaces do Delphi funcionam melhor quando são vinculadas a um GUID pois a base para verificar se uma classe implementa uma determinada interface é a função QueryInterface introduzida pelo IUnknown e usada à exaustão quando se trabalha com interfaces. E essa função pede uma identificação única na forma de um GUID para a interface que se deseja pesquisar ou instanciar. Você pode pressionar as teclas <Ctrl-Shift-G> no IDE do Delphi para ter um novo GUID gerado. Ao declarar uma interface, inclua o GUID como no exemplo:
IWSortable = interface
['{7CEF3AE4-9127-460E-B1A1-8D18B7CA7D05}']
function CompareTo (Elemen: IWSortable): Integer;
end;
['{7CEF3AE4-9127-460E-B1A1-8D18B7CA7D05}']
function CompareTo (Elemen: IWSortable): Integer;
end;
Volto em outra oportunidade com esse assunto para mostrar um implementação funcional de interface de sort.
Nenhum comentário :
Postar um comentário
OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.
Observação: somente um membro deste blog pode postar um comentário.