views:

1141

answers:

6

I'm looking to create a singleton in Delphi. I've done this before using older versions of Delphi, and ended up using global variables (in the implementation section) and using initialization and finalization to take care of the instance. Also there was no way of preventing the user from creating an instance as you couldn't hide the standard constructor. I was wondering if any of the new features such as class constructors and destructors, and class variables (ok, not so new), perhaps generics, could help in creating a generic singleton class. I haven't managed to create something to my satisfaction yet.

A: 

For a singleton, you can override the NewInstance method. And use a class variable. You create the variable at first call and return the pointer to the class each other call.

You just need to find someting to destroy it in the end (probably using the finalize).

Gamecat
or a class destructor in D2010.
Gerry
+6  A: 

In Delphi 2010 by far, the best and safest way is to use class constructors. See here - read especially the paragraph called Improved encapsulation.

HTH.

It's a shame that they didn't bother to document this feature properly, or include it in the "What's New" in the help.
IanH
+2  A: 

I prefer to use interfaces when I need singletons and hide the implementation of the interface in the implementation section.

benefits

  • Automatic destruction when the program terminates.
  • No way to accidently create a TMySingleton.

drawbacks

  • Someone might decide to implement IMySingleton on its own.

Note: I believe the use of Singletons should be kept to an absolute minimum. All in all, Singletons are little more than glorified global variables. If and when you start unit testing your code, they become a nuisance.

unit uSingleton;

interface

type
  ISingleton = interface
    ['{8A449E4B-DEF9-400E-9C21-93DFA2D5F662}']
  end;

function Singleton: ISingleton;

implementation

uses
  SyncObjs;

type
  TSingleton = class(TInterfacedObject, ISingleton);

var
  Lock: TCriticalSection;

function Singleton: ISingleton;
const
  _singleton: ISingleton = nil;
begin
  if not Assigned(_singleton) then
  begin
    Lock.Acquire;
    try
      if not Assigned(_singleton) then
        _singleton := TSingleton.Create();
    finally
      Lock.Release;
    end;
  end;
  Result := _singleton;
end;

initialization
  Lock := TCriticalSection.Create;
finalization
  Lock.Free;

end.
Lieven
+1 for the italic part on singletons.
mghie
@mghie: you disagree on the implementation of the pattern?
Lieven
I agree with you that most uses of the Singleton pattern are no progress compared to global variables. But if one wants to have them (for whatever reason), then a thread-safe generic solution would be necessary. Yours is definitely not, so you may actually end up with more than one instance. At least it doesn't leak memory, something I have seen in large commercial libraries where objects are used for the singleton implementation instead of interfaces. Moritz' solution looks like it might be thread-safe, but that would have to be checked thoroughly.
mghie
@mghie: point taken but to make this thread safe would only require one lock and unlock in the function creating the singleton. I'll adjust to make this "pattern" thread safe.
Lieven
A lock is going to affect all callers of the function, overhead that may not be good in some cases. There is an interesting lock-free initialization using `InterlockedCompareExchange` in OmniThreadLibrary code, see the blog post for more information: http://17slon.com/blogs/gabr/2009/02/hassle-free-critical-section.html
mghie
@mghie: we are still on Delphi 5. I'm not sure if the solution presented in the blog can be modified to work with Delphi 5. As for the *affect all callers*, the double check on Assigned eliminates the overhead.
Lieven
Your implementation only works with Writable Constants, which are default of for Delphi 7? and higher. You can also add _mySingleton as a var in the implementation section.
The_Fox
@The_Fox: bad habbits die slow...
Lieven
+8  A: 

If you just need a plain singleton, the simplest way is to use class constructors and class methods as suggested by plainth. But generics are very helpful if you need singletons with construction on demand (i.e. on first access).

The following code is taken from one of my utility units; it basically provides a generic singleton factory for Delphi 2009 onwards.

interface

type
  {$HINTS OFF}
  { TSingletonInstance<> implements lazy creation, which is sometimes useful for avoiding
    expensive initialization operations.
    If you do not require lazy creation and you target only Delphi 2010 onwards, you should
    use class constructors and class destructors instead to implement singletons. }
  TSingletonInstance<T: class, constructor> = record
  private
    FGuard: IInterface;
    FInstance: T;
    function GetInstance: T;
    function CreateInstance: TObject;
  public
    property Instance: T read GetInstance;
  end;
  {$HINTS ON}
  TSingletonFactoryFunction = function: TObject of object;

{ Private symbols (which are in the interface section because of known limitations of generics) }
procedure _AllocateSingletonInstance (InstanceRecord: Pointer; Factory: TSingletonFactoryFunction);

implementation

{ TSingleton }

var
  SingletonCriticalSection: TRTLCriticalSection;

type
  TSingletonGuard = class (TInterfacedObject)
  private
    FSingletonInstance: TObject;
  public
    constructor Create (AInstance: TObject);
    destructor Destroy; override;
  end;

  PUntypedSingletonInstance = ^TUntypedSingletonInstance;
  TUntypedSingletonInstance = record
    FGuard: IInterface;
    FInstance: TObject;
  end;

  // TODO: is a lock required for multiple threads accessing a single interface variable?
procedure _AllocateSingletonInstance (InstanceRecord: Pointer; Factory: TSingletonFactoryFunction);
var
  USI: PUntypedSingletonInstance;
begin
  USI := PUntypedSingletonInstance (InstanceRecord);
  EnterCriticalSection (SingletonCriticalSection);
  if USI.FInstance = nil then
  begin
    USI.FInstance := Factory ();
    USI.FGuard := TSingletonGuard.Create (USI.FInstance);
  end;
  LeaveCriticalSection (SingletonCriticalSection);
end;

constructor TSingletonGuard.Create (AInstance: TObject);
begin
  FSingletonInstance := AInstance;
end;

destructor TSingletonGuard.Destroy;
begin
  FSingletonInstance.Free;
  inherited;
end;

function TSingletonInstance<T>.GetInstance: T;
var
  Factory: TSingletonFactoryFunction;
begin
  if FInstance = nil then
  begin
    Factory := Self.CreateInstance; // TODO: associate QC report
    _AllocateSingletonInstance (@Self, Factory);
  end;
  Result := FInstance;
end;

function TSingletonInstance<T>.CreateInstance: TObject;
begin
  Result := T.Create;
end;

initialization
  InitializeCriticalSection (SingletonCriticalSection);
finalization
  DeleteCriticalSection (SingletonCriticalSection);

Usage as follows:

type
  TMySingleton = class
  public
    constructor Create;
    class function Get: TMySingleton; static;
  end;

var
  MySingletonInstance: TSingletonInstance<TMySingleton>;

class function TMySingleton.Get: TMySingleton;
begin
  Result := MySingletonInstance.Instance;
end;
Moritz Beutel
Great code Moritz.
Nick Hodges
Thanks. In fact it would be prettier if I could remove the workarounds for D2009 :)
Moritz Beutel
+2  A: 

It was possible to manage this by overriding the TRUE allocator and deallocator methods in Delphi, NewInstance and FreeInstance. Constructors and Destructors in Delphi only initialise and finalise respectively, they do not allocate or deallocate memory, so attempting to hide constructors was always a little misguided.

i.e. it was possible to allow free use of any and all constructors as long as you overrode NewInstance such that it only ever returned a reference to one single allocation of memory for the class.

But attempting to enforce a usage/behavioural pattern in a base class is a mistake imho. Not ALL patterns are or require specific classes to encapsulate the pattern.

In cases such as this you end up creating something that is needlessly complicated, and complication attracts errors in my experience and the object of the exercise then becomes trying to find flaws in the pattern implementation and then trying to implement safeguards against those flaws, rather than getting on with the practical job of work that the singleton class was supposed to perform.

It is far, FAR simpler and more effective to document the USAGE of the class.

Documentation as a technique for implementing this pattern has worked flawlessly for 15 years for the Application and Screen objects in the VCL, for example, not to mention countless other singletons that I've created in those years.

Deltics
A: 

I prefer to create singleton class using a code generator. The problem with generic is that, all code is generated in memory, not in source file. It will increase the difficulty of debugging.

stanleyxu2005