Board index » delphi » Q: Implementing the Singleton Design Pattern?

Q: Implementing the Singleton Design Pattern?

I'm trying to implement the Singleton design pattern, i.e. a class
that can only have a single instance.  So far I can't get it to work.

The example I've seen (in C++) uses a static member function which
returns the pointer for the single instance for the class.  If the
instance has not been created the static member function creates the
instance and then returns it's pointer.  A private static member
variable is used to hold the pointer of the single instance.

Am I right in thinking I cannot do this in Delphi?   Delphi doesn't
have static member variables, right?  But a class function is
equivalent to a static member function?

Any ideas?

thanks

Phillip B.
phillip.ba...@clear.net.nz

 

Re:Q: Implementing the Singleton Design Pattern?


On Thu, 27 Mar 1997 10:27:59 GMT, phillip.ba...@clear.net.nz (Phillip

Quote
A. Baird) wrote:
>I'm trying to implement the Singleton design pattern, i.e. a class
>that can only have a single instance.  So far I can't get it to work.

You can approach this in a couple different ways:

1. Use a class or global function to return an object instance. Tell
the user not to call Create to create any other instances.

2. Override NewInstance and FreeInstance. The first time NewInstance
is called, it calls its inherited method to create the object for
real. After that, it always returns the same object. FreeInstance does
nothing. (This results in an insignificant memory leak. Delphi will
clean up the memory anyway, but some tools might report the leak.)

This is probably the best approach because TObject.Create is public.
This means you can always create an instance of any object.

Quote
>Am I right in thinking I cannot do this in Delphi?   Delphi doesn't
>have static member variables, right?  But a class function is
>equivalent to a static member function?

Delphi does not have the equivalent of static data members, but it has
units. You can store private variables in the implementation part of a
unit.
--
Ray Lischner             (send email to "lisch" at tempest-sw.com)
Author of Secrets of Delphi 2 (http://www.tempest-sw.com/secrets/)

Re:Q: Implementing the Singleton Design Pattern?


In article <5hdi4l$12...@fep4.clear.net.nz> phillip.ba...@clear.net.nz (Phillip A. Baird) writes:

Quote
>I'm trying to implement the Singleton design pattern, i.e. a class
>that can only have a single instance.  So far I can't get it to work.
>The example I've seen (in C++) uses a static member function which
>returns the pointer for the single instance for the class.  If the
>instance has not been created the static member function creates the
>instance and then returns it's pointer.  A private static member
>variable is used to hold the pointer of the single instance.
>Am I right in thinking I cannot do this in Delphi?

YOU cannot do it YET,but that doesn't mean it can't be done.

Quote
>   Delphi doesn't
>have static member variables, right?  But a class function is
>equivalent to a static member function?

Define your class in a unit, which declares in its implementation
section a pointer initilazed to nil (typed constant, or use
initialization section) . Your Create function can check this
pointer to see if it is nil.
Mark Horridge email: mark.horri...@buseco.monash.edu.au

Re:Q: Implementing the Singleton Design Pattern?


But you can have global variables (that are equivalent to C++'s
statics).
Just declare a global in the unit. A rough sketch might be:

unit MySingleton;

interface

class
  Singleton = class
    constructor Create;
    (*add whatever you want here*)
  end;

function TheSingleton: Singleton;

implementation

var
  uniqueInstance: Singleton = nil;

constructor Create;
(* Attempts to create a Singleton object will cause an error *)
begin
  raise (* whatever exception is appropriate *)
end;

function TheSingleton: Singleton;
begin
  if not Assigned(uniqueInstance) then begin
    (* create an object for uniqueInstance *)
  end;
  Result := uniqueInstance;
end;

end.

Regards,
Joachim

Re:Q: Implementing the Singleton Design Pattern?


Quote
Phillip A. Baird wrote:

> I'm trying to implement the Singleton design pattern, i.e. a class
> that can only have a single instance.  So far I can't get it to work.

> The example I've seen (in C++) uses a static member function which
> returns the pointer for the single instance for the class.  If the
> instance has not been created the static member function creates the
> instance and then returns it's pointer.  A private static member
> variable is used to hold the pointer of the single instance.

> Am I right in thinking I cannot do this in Delphi?   Delphi doesn't
> have static member variables, right?  But a class function is
> equivalent to a static member function?

> Any ideas?

> thanks

> Phillip B.
> phillip.ba...@clear.net.nz

Here is an example that represents the private static in Delphi

unit StaticEx;

type TObjClass = class(TObject)
     ... here comes the methods and the properties
     end;

var Obj: TObjClass

implementation

var StaticCounter: longint;      <--- This is a static variable.

procedure ObjClass.Create(....);
begin
  StaticCounter := StaticCounter + 1;
end;      

end;

Re:Q: Implementing the Singleton Design Pattern?


Thanks to those who assisted with this problem.  Below is the class I
ended up creating.

It features a global StringList to keep track of instance pointers.
I've done this so the Singleton can be sub-classed without need of a
new global variable.

The NewInstance method has been overwritten to raise an exception if
the constructor is called directly.  I'm not sure if this eats any
memory but it's mainly there to catch any coding mistakes.

Feel free to comment on my code or methodology.

Phillip Baird
phillip.ba...@clear.net.nz

unit Singleton;

interface

uses
  SysUtils, Classes;

type

  TSingleton = class(TObject)
  public
    destructor Destroy; override;
    class function Instance: TSingleton;
    class function NewInstance: TObject; override;
  end;

  ESingleton = class(Exception);

implementation

var
  InstanceList: TStringList;

destructor TSingleton.Destroy;
begin
  if Assigned(InstanceList) then
  with InstanceList do
  begin
    // Remove singleton from Instance list.
    Delete(IndexOf(Self.ClassName));
    // Free the list if empty.
    if Count = 0 then
    begin
      Free;
      InstanceList := Nil;
    end;
  end;
  inherited Destroy;
end;

class function TSingleton.Instance: TSingleton;
var
  Index: Integer;
begin
  // Create the global instance list.
  if not Assigned(InstanceList) then
  begin
    InstanceList := TStringList.Create;
    InstanceList.Sorted := True;
  end;

  // Return existing instance or create a new instance.
  if InstanceList.Find(ClassName, Index) then
    Result := TSingleton(InstanceList.Objects[Index])
  else
  begin
    Index := InstanceList.Add(ClassName);
    Result := Create;
    InstanceList.Objects[Index] := Result;
  end;
end;  // TSingleton.Instance

class function TSingleton.NewInstance: TObject;
  procedure Error;
  begin
    raise ESingleton.Create('Singleton constructor cannot be called
directly. Use Instance method.');
  end;
var
  Index: Integer;
begin
  // Raise Exception if constructor called directly.
  if not Assigned(InstanceList) then Error;
  Index := InstanceList.IndexOf(ClassName);
  if (Index = -1) or ((Index <> -1) and (InstanceList.Objects[Index]
<> Nil)) then Error;
  // Return a new instance.
  Result := inherited NewInstance;
end;

end.

Other Threads