Reputation: 3259
I have three classes, for example (TMyClass1, TMyClass2, and TMyClass3).
I have a function that takes as a parameter a string with the name of the type, and then instanciates that class given the type. Right now I'm using if statements, for example:
if(AFormName = 'xxx1') then
begin
MyClass := MyClass1.Create;
end else if(AFormName = 'xxx2') then
begin
MyClass := MyClass2.Create;
end;
Etc..
Is there a way that I can store the type in a variable so I change link the strings to the types and avoid using that?
If it's any help, MyClass1, MyClass2 and MyClass3 all inherit from another class...
Upvotes: 3
Views: 823
Reputation: 598299
Look at the RTL's RegisterClass()
and FindClass()
/GetClass()
functions, they were designed for exactly this kind of scenario, eg:
interface
uses
..., Classes;
type
MyBase = class(TPersistent)
public
constructor Create; virtual;
end;
MyBaseClass = class of MyBase;
MyClass1 = class(MyBase)
public
constructor Create; override;
end;
MyClass2 = class(MyBase)
public
constructor Create; override;
end;
MyClass3 = class(MyBase)
public
constructor Create; override;
end;
...
function MakeMyClass(const Name: string): MyBase;
implementation
function MakeMyClass(const Name: string): MyBase;
begin
Result := MyBaseClass(GetClass(Name)).Create;
end;
...
initialization
RegisterClasses([MyClass1, MyClass2, MyClass3{, ...}]);
end.
Then you can do this:
var
MyObj: MyBase;
begin
MyObj := MakeMyClass('MyClass1');
...
MyObj.Free;
end;
The drawback is that the classes must be derived from TPersistent
. If you don't want to use TPersistent
, or if you just want to use different names to create your class objects, it is not very hard to setup a custom factory, for instance by using a TDictionary
, eg:
interface
type
MyBase = class
public
constructor Create; virtual;
end;
MyBaseClass = class of MyBase;
MyClass1 = class(MyBase)
public
constructor Create; override;
end;
MyClass2 = class(MyBase)
public
constructor Create; override;
end;
MyClass3 = class(MyBase)
public
constructor Create; override;
end;
...
function MakeMyClass(const Name: string): MyBase;
implementation
uses
System.Generics.Collections, System.SysUtils;
var
MyFactory: TDictionary<string, MyBaseClass>;
function MakeMyClass(const Name: string): MyBase;
begin
Result := MyFactory[Name].Create;
end;
...
initialization
MyFactory := TDictionary<string, MyBaseClass>.Create;
MyFactory.Add('xxx1', MyClass1);
MyFactory.Add('xxx2', MyClass2);
MyFactory.Add('xxx3', MyClass3);
finalization
MyFactory.Free;
end.
Then you can do this:
var
MyObj: MyBase;
begin
MyObj := MakeMyClass('xxx1');
...
MyObj.Free;
end;
Upvotes: 12