Implementing the Singleton Design Pattern in Delphi without Global Variables

The purpose of this post is NOT to cover the insights and applicability of the Singleton pattern, instead  I just pretend to give you a Delphi code snipped that implements it. This implementation is focused in avoiding variables that are global to the unit (or Unit Global Variables).

Fist of all, I am borrowing the definition and UML diagram of the Singleton Design Pattern, as written in the Design Patterns: Elements of Reusable Object-Oriented Software book. I strongly suggest you to read this book if you want to have a deeper understanding of the classic design patterns.

Singleton: “Ensure a class only has one instance, and provide a global point of access to it.”

UML diagram:

UML diagram of the Singleton Design Pattern
For all Delphi versions previous to Delphi 7, the only way to implement this pattern is by using a Unit Global Variable, instead of a class static field. Fortunately, Delphi 7 featured class variables long time ago and this way, we can implement the pattern avoiding global scoped variables. For some reason, I have never seen an implementation of the Singleton pattern in Delphi using class variables, so here is my own:

unit Singleton;

interface

type
  TSingleton = class
  private
    //Private fields and methods here...
   
    (****************************************************)
    (*** Class variables were introduced in Delphi 7. ***)
    (*** Older Delphi versions should implement       ***)
    (*** this field as a unit global variable         ***)
     class var _instance: TSingleton;   
    (****************************************************)
  protected
    (*** Constructor is protected!!! ***)
    constructor Create;

    //Other protected methods here...
  public
    destructor Destroy; override;

    (********************************************)
    (*** Client code should use this function ***)

    (*** ("Instance"), instead of the         ***)
    (***
"constructor" to create (or access)  ***)
    (*** a singleton instance.                ***)
    class function Instance: TSingleton;
    (********************************************)
    

    class function NewInstance: TObject; override;

    //Other public methods and properties here...
  end;

implementation

{ TSingleton }

constructor TSingleton.Create;
begin
  inherited Create;
end;

destructor TSingleton.Destroy;
begin
  _instance:= nil;
  inherited;
end;

class function TSingleton.Instance: TSingleton;
begin
  if (_instance = nil) then
    _instance:= TSingleton.Create;

  result:= _instance;
end;



class function TSingleton.NewInstance: TObject;
begin
  if (_instance = nil) then
    _instance:= inherited NewInstance as Self;

  result:= _instance;

end;

end.


There was a problem with my original implementation. In Delphi:
  • Constructors are inherited (this doesn't happen in C++, Java, C#, etc.)
  • All classes inherit from TObject ultimately.
As TObject has its own constructor, the consumers of the TSingleton class can call it directly, allowing this way the creation of more than one instance. Ali, writer of the first comment in this article, pointed me in the right direction.  Thanks Ali.

I traduced Ali’s words into the source code above. The strikethrough text can be removed and the text in blue was added. This implementation ensures the singleness of the Singleton Design Pattern in Delphi.

Rethinking over this once again:

The implementation above ensures the class only has one instance; but it does not provide a global point of access to it. Instead of that, we now have two points of access. Take a look at the following code snipped:

  //Point of access ONE
  SingletonObject1:= TSingleton.Create;
 
  //Point of access TWO
  SingletonObject2:= TSingleton.Instance; 

Yes, two point of access: TSingleton.Create and TSingleton.Instance.

Rethinking this many times, I figured out the simplest implementation. We don’t even need to deal with the evil NewInstance class function. It looks like this:

unit Singleton;

interface

type
  TSingleton = class
  private
    //Private fields and methods here...

     class var _instance: TSingleton;
  protected
    //Other protected methods here...
  public
    //Global point of access to the unique instance
    class function Create: TSingleton;

    destructor Destroy; override;

    //Other public methods and properties here...
  end;

implementation

{ TSingleton }

class function TSingleton.Create: TSingleton;
begin
  if (_instance = nil) then
    _instance:= inherited Create as Self;

  result:= _instance;
end;

destructor TSingleton.Destroy;
begin
  _instance:= nil;
  inherited;
end;

end.

The only point of access to the singleton instance is the class function “Create”, which hides the TObject.Create parameterless constructor (more details here). Now we have only one instance and a global point of access to it.

The comments inside the above code are self-explanatory. Furthermore, for those stuck with older Delphi versions, the Singleton pattern should be implemented as follows:

unit Singleton;

interface

type
  TSingleton = class
  private
    //Private fields and methods here...
  protected
    //Other protected methods here...
  public
    //Global point of access to the unique instance
    class function Create: TSingleton;

    destructor Destroy; override;

    //Other public methods and properties here...
  end;


var
  _instance: TSingleton;
//Unit Global Variable.
 

implementation
...................

As a conclusion, I would suggest avoiding unit global variables as much as possible; in fact, as a rule of thumb, I would suggest to make your variables' scope as local as possible. This applies not only to this example (implementation of the Singleton Design Pattern), but to programming in general. Furthermore, the class variables in Delphi are equivalent to static member variables in C++, Java, C#...Class variables were introduced  in Delphi 7; so, previous versions should use global variables to implement a Singleton class.

Note:
There are three books about Design Patterns I would suggest you to read:

Design Patterns: Elements of Reusable Object-Oriented Software

Head First Design Patterns

Object Models: Strategies, Patterns, and Applications (2nd Edition)

6 comments:

  1. The problem with your implementation is user can simply call the constructor to create new instances of the class. Hiding the constructor in your class will not hide constructor of TObject class.

    To have a better implementation, you can override NewInstance method of TObject, and make it to return _Instance if _Instance is assigned. This way, even calling the constructor will return the same instance of the class. To destroy the instance, you can use a class destructor.

    Best Regards,
    Ali

    ReplyDelete
  2. Thanks Ali. You are right. I am going to update this article ASAP and the credit about this finding will remain yours. Once again, thanks.

    Yanniel (Blog owner)

    ReplyDelete
  3. Just stumbled across your post. Another alternative:

    interface
    type
    ISingleton = interface
    // you know what goes here.
    end;

    function Singleton: ISingleton;

    implementation

    type
    TSingleton = class(TInterfacedObject, ISingleton)
    // You know what goes hear also
    end;

    var Instance: ISingleton;

    function Singleton: ISingleton;
    begin
    if not Assigned(Instance) then
    Instance := TSingleton.Create;
    end;

    This meets both requirements of the singleton pattern and has the added benefit of referenced counted memory management.

    Your implementation would've been easier to accomplish if Delphi actually enforced 'class abstract' but in most cases it doesn't even issue a warning.

    ReplyDelete
  4. Hi codeelegance. Thanks for your comment.

    Yes, with your implementation we don't have to remember about freeing the memory, but it has two issues:

    1.) A Global Variable (var Instance: ISingleton;) is being used. I don't want to use global variables as you can see in the title of this post ;-)

    2.) A user could still chose to call
    Instance2 := TSingleton.Create;
    instead of
    Instance2 := Singleton;
    In the case above there's no singleness. Spot the difference? This is explained in the body of the post.

    I don't fully understand what you meant with "...if Delphi actually enforced 'class abstract' but in most cases it doesn't even issue a warning."

    Any feedback is welcome.

    ReplyDelete
  5. Just wondering if I could get your permission to use your singleton example in a blog/book I'm working on?

    ReplyDelete
    Replies
    1. Sure, just reference me as contributor of the singleton example.

      Delete