Delphi Base Class Factory

Im not sure if this is a good pattern or not, or if you can do something simillar in Java, c plus plus etc.. But here goes

-SteveEyles

It could be better. You're using a switch on the type in a palce where you should be using virtual method calls.This also makes the base class dependent on all its subclasses.

As a matter of fact DelphiLanguage doesn't need the factory pattern because it has Factory, AbstractFactory and a few other DesignPatterns are in fact workarounds for languages with limited abilities. So here's how you can fix it:

 Define a virtual constructor on the base class.
 Define a collection indexed by TApeType (or even a string) that returns class of TApe
 Call the virtual constructor: return myTypes[index].create(...)

This way you replace the case ... statement with a virtual call. It is slightly more elegant, and it allows for greater flexibility, you can make the factory mechanism. Delphi is quite unique among typed OO languages in the sense that it allows virtual constructors. --CostinCozianu


  interface

type TApeType = (atGorilla, atOrangutan, atChimp);

EUnknownApe = class(Exception);

TApe = class(TObject) public class function CreateFactory(const ApeType : TApeType) : TApe; end;

TGorilla = class(TApe); TOrangutan = class(TApe); TChimp = class(TApe);

implementation

class function TApe.CreateFactory(const ApeType : TApeType) : TApe; begin case ApeType of atGorilla: Result := TGorilla.Create; atOrangutan : Result := TOrangutan.Create; atChimp: Result := TChimp.Create; else raise EUnknownApe.Create; end; end;


I can now dynamically create one of the 3 descendent classes without needing to see there interfaces, I only need to see the interface of TApe. (In actual use the 3 descendants would be in separate units). Putting 'class' in front of a method is the same as using 'static' in C plus plus


Some refactoring:

  interface

type TApeType = (atGorilla, atOrangutan, atChimp);

TApe = class(TObject) public class function CreateFactory(const ApeType : TApeType) : TApe; end;

TApeClass = class of TApe;

TGorrila = class(TApe); TOrangutan = class(TApe); TChimp = class(TApe);

implementation

const theApeClasses: array[TApeType] of TApeClass = (TGorrila, TOrangutan, TChimp);

class function TApe.CreateFactory(const ApeType : TApeType) : TApe; begin Result := theApeClasses[ApeType].Create; end;


More refactoring:

  interface

type

TApe = class(TObject) public class function CreateApe(const ApeType : TApeType) : TApe; end;

TApeClass = class of TApe; TApeType = TApeClass;

TGorrila = class(TApe); TOrangutan = class(TApe); TChimp = class(TApe);

implementation

class function TApe.CreateApe(const ApeType : TApeType) : TApe; begin Result := TpeType.Create; end;


yet more refactoring:

  TApe = class(TObject)
  public
constructor Create; virtual;
  end;


Actually, the class factory should be really that: a class factory. It returns the class you want to instantiate, leaving instantiating up to you. You can design the getApsClass function to take a string parameter, or an int, or anything else you might desire -- it doesn't matter. It gives you a class of TApe you can call Create() on. I prefer this to returning an instantiated object.--ATS.

  interface

type

TApe = class(TObject) public constructor Create; virtual; class function getApeClass() : TApeClass; end;

TApeClass = class of TApe;

TGorrila = class(TApe); TOrangutan = class(TApe); TChimp = class(TApe);

implementation

...

{somewhere in your code}} TApe.getApeClass().Create();


EditText of this page (last edited November 12, 2007) or FindPage with title or text search