quarta-feira, 3 de agosto de 2011

Singleton em Delphi utilzando interfaces

Olá, dando sequencia ao post anterior sobre Singleton, hoje irei mostrar uma implementação alternativa, e ao meu ver, mais elegante.

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.

2 comentários:

  1. O ruim é que não tem como usar propriedades neste modelo.

    ResponderExcluir
  2. Olá Jair, obrigado pelo comentário.

    Na 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

    ResponderExcluir