unit uSingletonDerivado;

interface

uses
  uSingleton, SysUtils, DateUtils, Windows, dialogs;

type

  TObjetoUnicoDerivado = class(TObjetoUnico)
  private
    FDataHora: string;
  public
    constructor Create;
    class function CreateUnico: TObjetoUnicoDerivado;
    destructor Destroy; override;
    function GetDataHora: string;
  end;

procedure VerificaObjetoUnicoDerivadoCriado;

implementation

var
  _ObjetoUnico: TObjetoUnicoDerivado;
  _Contador: Integer = 0;

procedure VerificaObjetoUnicoDerivadoCriado;
begin
  if (_Contador >= 1) and (_ObjetoUnico <> nil) then
    ShowMessage('=========== verificação ===========' + #13#10 +
    'Nome da classe: ' + _ObjetoUnico.ClassName+ #13#10 +
    'Hora de Criação: ' + _ObjetoUnico.GetDataHora + #13#10 +
    'Endereço na memória: ' + IntToStr(Integer(_ObjetoUnico))
  );
end;

{ TObjetoUnicoDerivado }

constructor TObjetoUnicoDerivado.Create;
begin

    if (_Contador = 0) then
    begin
      //aqui há o perigo de criar mais um objeto _ObjetoUnico que perderá sua referência e causará leak
      //ou, no mínimo, incrementar o seu contador
      //experimente descomentar o inherited para ver o que acontece
      //inherited Create;
      InterlockedIncrement(_Contador);
      FDataHora := FormatDateTime('yyyy-mm-dd hh:nn:ss', now);
    end
    else
      raise Exception.Create('Ei! Não use esse constructor, use o CreateUnico!');
    //o inherited fica dentro do if assim o objeto não será criado caso ja esteja o contador > 0

end;

class function TObjetoUnicoDerivado.CreateUnico: TObjetoUnicoDerivado;
begin
  //aqui não se pode usar inherited porque senão trará uma instância do objeto ancestral
  if _ObjetoUnico = nil then
    _ObjetoUnico := TObjetoUnicoDerivado.Create;
  Result := _ObjetoUnico;
end;

destructor TObjetoUnicoDerivado.Destroy;
begin
  _ObjetoUnico := nil;
  InterlockedDecrement(_Contador);
  //aqui há o perigo de destruir um objeto _ObjetoUnico que pode estar em uso na unit do ancestral
  //expedrimente descomentar o inherited para ver o que acontece
  //inherited;
end;

function TObjetoUnicoDerivado.GetDataHora: string;
begin
  //aqui não haveria perigo de chamar inherited
  //mas se você não chamar o inherited do create então  o campo privado
  //FDataHora ficará vazio (seria usado o do ancestral)
  //por isso é melhor refazer
  //isso é polimorfismo :)
  Result := 'Data desta classe nova: ' +  FDataHora;;
end;

initialization
  _ObjetoUnico := nil;
  _Contador := 0;

finalization
  if (_ObjetoUnico <> nil) then
  try
    _ObjetoUnico.Free;
  except
    //tratamento de excessão
  end;


end.
