1

I have many singletons where I don't want the developers to call the constructor Create. Instead they should use the function Instance

TdgpBankBranch = class(TDataGroup)
strict private
  class var InstanceVar : TdgpBankBranch;
private
  { Only for internal use }
  constructor Create (AOwner : TComponent); reintroduce;
protected
public
  class function Instance : TdgpBankBranch;
  class function Is_A_Live_Singleton: boolean;
  property Rec[Bank, Branch : integer]: TBankBranch read GetRec; default;
end;

I have been shifting the constructors to private. This makes the code analysers complain "Non-public constructor".

I could shift them back to public. Is there a way to make the compiler fail if an attempt is made at using the constructor ?

Rohit Gupta
  • 4,022
  • 20
  • 31
  • 41

2 Answers2

2

Moving the constructor to private will prevent other units from being able to call Create() directly, however code inside the same unit as the class will still be able to call it unhindered, due to implicit friendship within a unit. If you don't want any code outside of the class calling Create() directly, even in the same unit, then declare it as strict private so only the class itself can call it directly.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    Even with a strict private Create, wouldn't the `TObject.Create` be seen by the compiler (or whatever inherited Create has higher visibility)? – Uwe Raabe Jul 03 '15 at 06:00
  • @Uwe, yes, it will. But I wouldn't personally stress about whether the constructor of that class is hidden. If you use a class, everyone can `Free` that singleton instance, which is even worse. I'd say that ideal would be having a factory that will return an interface reference, an interface implemented by a persistent class (that is no `TInterfacedObject`) having a singleton instance *sitting* inside the factory. – TLama Jul 03 '15 at 06:16
  • @Remy, Making it strict private does not solve my problem. I use Delphi instead of C because I want the compiler to do the grunt work, not the end user. And I want remove human error out of it. My solution does that. My developers can not call Create from outside. The only problem is that I have been using Peganza for a while and I want to get to a point where if it flags something, its worth looking at. So, every so often I wonder if I can do it better. – Rohit Gupta Jul 03 '15 at 08:42
1

You ask how to stop the compiler from creating an object when somebody calls .create, but what you're trying to do is create a singleton, so it helps to see how others solved this.

In Delphi, singletons are often implemented via a function that's declared in the interface section and which returns an object that's declared in the implementation section of a unit. The function creates the instance if it doesn't exist yet, to provide lazy loading. Cleanup is done via the finalization section.

In your situation, instead of having an instance() function, you just create a global function that gives you an instance.

This approach probably stems from the days before classes and private sections existed, but it's pretty straightforward, and prevents the issue that you're running in to. Look at how TClipboard is implemented. This implementation is not possible in Java or C# because they don't have global functions, or the type of scoping that makes this Delphi implementation work...

Or take a look at this answer by David Heffernan: Delphi Singleton Pattern

It's even better than TClipboard, because it hides the entire class in the implementation section, truly preventing people to create instances themselves, but you'll have to create an interface for your class.

Community
  • 1
  • 1
Wouter van Nifterick
  • 23,603
  • 7
  • 78
  • 122
  • This is the problem when you start with Delphi 1. You don't realise whats been added over the years. I agree, Davids solution is elegant and does what I want. I will give you the tick since you have pointed me to it. :-) – Rohit Gupta Jul 03 '15 at 08:44