Singleton pattern

Origin

This singleton pattern is based on the singleton pattern as described in [Gam+, pages 127..134]. The Delphi implementation for the pattern originates from White Ants.

Intent

Ensure a class only has one instance, and provide a global point of access to it [Gam+,p127].

Motivation

The motivation is based on [Gam+, page 127]. It’s important for some classes to have exactly one instance. Although there can be many printers in a system, there should be only one printer spooler. There should be only one file system (or file system manager) and one window manager.

How do we ensure that a class has only one instance and that the instance is easily accessible? A global variable makes an object accessible, but it doesn’t keep you from instantiating multiple objects. Global variables also tend to pollute the name space.

A better solution is to make the class itself responsible for keeping track of it’s sole instance. The class can ensure that no other instance can be created (by intercepting requests to create new objects), and it can provide a way to access the instance. This is the singleton pattern. Typical use of this pattern is in service like classes.

Implementation

Consider for example a class TProgressor which could be used as a low level service to deal with time consuming processes. Typical methods would be: StartProgress, EndProgress, Abort and typical properties would be Progress, Aborted etc. The following example shows part of TProgressor’s interface:

type
  TProgressor = class (TObject)
  private
    FProgress: Integer;
  protected
    procedure SetProgress(Value: Integer);
  public
    procedure StartProgress;
    property Progress: Integer read FProgress write SetProgress;
  end;

Applying the singleton pattern to this class results in the following interface:

type
  TProgressor = class (TObject)
  private
    FProgress: Integer;
  protected
    constructor CreateInstance;
    class function AccessInstance(Request: Integer): TProgressor;
    procedure SetProgress(Value: Integer);
  public
    constructor Create;
    destructor Destroy; override;
    class function Instance: TProgressor;
    class procedure ReleaseInstance;
    procedure StartProgress;
    property Progress: Integer read FProgress write SetProgress;
  end;

Let’s have a look at the public interface first: The class function Instance is used to access the single instance of this class. The first time this class method is called, the instance is actually created. The constructor Create is overridden to raise an exception if you attempt to create an instance without using the Instance method. This will prevent you from accidentally creating multiple instances. Calling ReleaseInstance will clean up the single instance if it existed. You would typically call this method in a clean up section. In Delphi 1.0 from an exit procedure, in Delphi 2.0 in a unit’s finalization section. Don’t call the TProgressor.Instance.Free to clean up the instance, since this will first create it, if it hadn’t been created before. Destroy co-operates in the instance bookkeeping.

Now let’s have a look at the actual implementation of this pattern.

constructor TProgressor.Create;
begin
  inherited Create;
  raise Exception.CreateFmt('Access class %s through Instance only',
      [ClassName]);
end;

constructor TProgressor.CreateInstance;
begin
  inherited Create;
end;

destructor TProgressor.Destroy;
begin
  if AccessInstance(0) = Self then AccessInstance(2);
  inherited Destroy;
end;

class function TProgressor.AccessInstance(Request: Integer): TProgressor;
  const FInstance: TProgressor = nil;
begin
  case Request of
    0 : ;
    1 : if not Assigned(FInstance) then FInstance := CreateInstance;
    2 : FInstance := nil;
  else
    raise Exception.CreateFmt('Illegal request %d in AccessInstance',
        [Request]);
  end;
  Result := FInstance;
end;

class function TProgressor.Instance: TProgressor;
begin
  Result := AccessInstance(1);
end;

class procedure TProgressor.ReleaseInstance;
begin
  AccessInstance(0).Free;
end;

procedure TProgressor.SetProgress(Value: Integer);
begin
  { Place here the implementation of the progress mechanism ]
end;

procedure TProgressor.StartProgress;
begin
  { Placehere the implementation of the progress mechanism ]
end;

The secret of this pattern is in the AccessInstance method. This method uses a typed constant to store the instance. We needed to use this work around because Delphi doesn’t support (static) class fields in classes. Depending on the parameter Request the method will either return the instance (Request = 0), create an instance (Request = 1), reset the instance to nil (Request =2). Delphi 2.0 allows this use of typed constants only if the $J+ compiler switch is set.

By making the constructor CreateInstance protected, we assure that no other class is able to call this constructor. It may however be made virtual and can be overridden in descendant classes. In that case the first class to call Instance will determine the actual type to be instantiated.

The only code you manually need to add, is the clean up code in the unit’s initialization or finalization section. This could be something like:

unit Progress;

...
...

implementation

...
...
 

procedure ShutDown;
begin
  TProgressor.ReleaseInstance;
end;

finalisation
  ShutDown;
end.

You can now use the TProgressor class as follows:

procedure TSomeClass.DoSomething;
var I: Integer;
begin
  TProgressor.Instance.StartProgress;
  for I := 0 to 100 do
  begin
    TProgressor.Instance.Progress := I;
  ..{ do something useful }
  end;
  TProgressor.Instance.EndProgress;
end;