Dec 01 2006
Tentativa de Singleton usando Delphi
O design pattern Singleton garante que somente uma instância de determinada classe estará disponível durante todo o ciclo de vida da aplicação.
Hoje precisei implementá-lo em uma aplicação servidora. Tenho uma estrutura assim:
- Arquivo de configuração XML (Configuracoes.xml);
- Classe que faz read/write neste arquivo (TXMLCfgClass);
- Classes que utilizam a TXMLCfgClass para acessarem as suas configurações (TServidorCfgClass, TBackupCfgClass, TBancoDadosCfgClass, etc.).
O mesmo arquivo XML será compartilhado pelas três classes de acesso às configurações, ou seja, uma única instância do objeto TXMLCfgClass deverá estar disponível para as três classes. Aqui é que entra o Singleton: ele garante que somente uma instância da classe TXMLCfgClass existirá durante todo o ciclo de vida da aplicação.
Tudo muito bonito e interessante na teoria. Na prática a coisa é um pouquinho diferente.
Tentei criar uma propriedade (ou field) privado e estático na classe TXMLCfgClass, mas não consegui. Uma solução semelhante é utilizar uma variável na seção implementation, desta forma:
1 implementation 2 3 var 4 xmlCfg: TXMLCfgClass;
class function TXMLCfgClass.GetInstance: TXMLCfgClass; begin // GetInstance if (xmlCfg = nil) then xmlCfg := TXMLCfgClass.Create; Result := xmlCfg; end;
A abordagem é muito interessante, pois se bem utilizada (chamando somente o método GetInstance) funcionará. No entanto, ainda é possível instanciar um objeto TXMLCfgClass utilizando o constructor Create.
Outra forma de implementar o Singleton é fazendo um override no método NewInstance da classe TObject. Encontrei este exemplo que é específico para o Delphi 5, no entanto, fiz os testes com o Delphi 6 e funcionou também.
Aqui também não são só flores. De acordo com o help do Delphi 6, ao fazer o override do NewInstance não devemos chamar inherited NewInstance no final, mas sim InitInstance. No exemplo que fiz, utilizei o inherited NewInstance e funcionou perfeitamente. O único detalhe é que não deve-se chamar o FreeAndNil após utilizar o objeto.
Veja o exemplo:
class function NewInstance: TObject; override;
class function TCliente.NewInstance: TObject; begin if (cliente = nil) then cliente := TCliente(inherited NewInstance); Result := cliente; end;
No fim das contas, acabei optando pela primeira opção. Faça os testes e escolha uma delas.
É isso aí! T+







