Nessa abordagem, o estado e/ou comportamento exposto pelo singleton deve ser declarado em uma interface.
type ISingleton = interface ['{F5B00272-536A-4C30-AB19-54496B106C7C}'] procedure FacaAlgo; end;
Após a interface, vamos criar uma classe que seja responsável por implementá-la. O detalhe importante é que a classe fique abaixo da seção implementation, isso garante que ninguém fora dessa unit terá acesso a classe, tornado impossível criar uma nova instância da mesma.
implementation type TSingletonInterface = class(TInterfacedObject, ISingleton) public procedure FacaAlgo; end; { TSingletonInterface } procedure TSingletonInterface.FacaAlgo; begin if IsConsole then Writeln(ClassName, ' Fazendo algo') else ShowMessageFmt('%s Fazendo algo', [ClassName]); end;
Agora precisamos de uma forma única de acessar uma instância dessa classe, para isso, vamos criar uma função e uma variável global privada para armazenar a instância. É importante que a função e variável fiquem, respectivamente, acima e abaixo da seção implementation, "blindando" o acesso a variável e a classe.
function GetSingleton: ISingleton; implementation var _Singleton: ISingleton = nil; function GetSingleton: ISingleton; begin if (_Singleton = nil) then _Singleton := TSingletonInterface.Create; Result := _Singleton; end;
Ao meu ver, essa é uma implementação melhor do que a do post anterior, pois o Singleton deixa mais claro sua intenção, seus métodos fazem exatamente o que está descrito, e por ser uma interface não existem os métodos Create e Free, que são públicos em TObject.
O código completo do exemplo pode ser acessado aqui.
O ruim é que não tem como usar propriedades neste modelo.
ResponderExcluirOlá Jair, obrigado pelo comentário.
ResponderExcluirNa verdade é possível sim declarar propriedades em interfaces, só não é possível declarar atributos, tendo obrigatoriamente que utilizar getter e setter.
Exemplificando, a declaração da interface ficaria assim:
type ISingleton = interface ['{F5B00272-536A-4C30-AB19-54496B106C7C}'] function GetAlgumaPropriedade: String; procedure SetAlgumaPropriedade(const Value: String); procedure FacaAlgo; property AlgumaPropriedade: String read GetAlgumaPropriedade write SetAlgumaPropriedade; end;
E os métodos GetAlgumaPropriedade e SetAlgumaPropriedade seria implementados normalmente na classe concreta, que teria também o atributo FAlgumaPropriedade, por exemplo.
type
TSingletonInterface = class(TInterfacedObject, ISingleton)
private
FAlgumaPropriedade: String;
function GetAlgumaPropriedade: String;
procedure SetAlgumaPropriedade(const Value: String);
public
procedure FacaAlgo;
end;
Abraços