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
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();