Hey guys

Hey guys,

How do I create a class which has only a private constructor? I have tried but doesn't work as expected. I am able to hide the constructor from Delphi IDE's auto-completion but the users are still able to call a parameterless constructor :( I want to implement the Builder pattern in Delphi and to achieve that I need to hide the class constructors thus the class can only be instantiated through the builder object.  I want something close to done here https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/Retrofit.java#L230-L244 :D

Thanks in advance :D

Comments

  1. I'm not an expert about pattern, but what your talking about looks like more an Interface than an object.

    ReplyDelete
  2. it's not possible to hide the inherited public constructor of an objet, you can only override it but it still public. That's why I've think about Interface that can not be instanciated :)

    ReplyDelete
  3. Paul TOTH :( Sorry sorry, that you wrote is right, I will think better about that :D Many thanks.

    ReplyDelete
  4. TMyObject = class
    public
      procedure Create;
    private
      constructor CreatePrim(aSomeParams : TSomeParams) : TMyObject;

    constructor TMyObject.CreatePrim(aSomeParams : TSomeParams) : TMyObject;
    begin
     inherited Create;
     f_Data := aSomeParams;
    end;

    procedure Create;
    begin
     Assert(false);
    end;

    ReplyDelete
  5. It's dangerous. If a constructor is hidden, you will often end up calling the ancestor class's constructor - without a warning from the compiler.  Uwe Raabe's link contains a workaround for this, to hide the inherited constructor(s) with methods with the same name.

    I was sure there was a QP report to add a compiler warning in this situation, to help prevent partially initialised objects, but I couldn't find one.  So I made one: https://quality.embarcadero.com/browse/RSP-11613

    ReplyDelete
  6. By the way, another way to approach this is to provide the interface, and have the implementing class entirely hidden - ie defined in a type clause in the implementation part of a unit.  To get an instance, external units can then only call the function you provide.

    It makes polymorphic OO via inheritance a bit more difficult though.

    ReplyDelete
  7. Uwe Raabe it handles only partially, you can still call it through a metaclass:

    type
       TDummy = class (TObject);
    var
       meta : TClass;
       obj : TObject;
    begin
       meta := TDummy;
       obj := meta.Create;

    now obj is a TSomeClass created with the original TObject constructor.

    Only fix would be to have the original TObject.Create constructor be virtual, rather than static.

    ReplyDelete
  8. Why not just use a record? No constructor to hide...

    ReplyDelete

Post a Comment