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