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