сase SomeValue of
1: Obj := TFirstClass.Create;
2: Obj := TSecondClass.Create;
...
end;
И это еще при том, что классы родственны между собой и их конструкторы имеют одинаковый прототип. Не нужно заниматься подобной ерундой, язык поддерживает виртуальные конструкторы! Все, что нужно, это объявить тип "классовая ссылка" (он же метакласс) таким образом:
TMyClass = class of TMyObject;
где TMyObject - общий предок для всех классов, экземпляры которых необходимо создавать, а также у класса TMyObject объявить виртуальный конструктор, который в потомках следует перекрывать. Например:
TMyObject = class(...)
public
constructor Create(SomeParam: SomeType); virtual;
...
end;
TFirstClass = class(TMyObject)
public
constructor Create(SomeParam: SomeType); override;
...
end;
Теперь создать экземпляр неизвестного на этапе компиляции класса можно например так:
function Factory(ClassType: TMyClass; Param: SomeType): TMyObject;
begin
Result := ClassType.Create(Param);
end;
Вызывать можно так:
Obj := Factory(TFirstClass, 10);
или
Obj := Factory(TSecondClass, 20);
Можно пойти дальше и реализовать фабрику, которая принимает на входе некое значение типа String, Integer или другого типа, находит в неком реестре сопоставленный этому значению класс и создает его экземпляр:
RegisterClassAlias(TFirstClass, '1');
RegisterClassAlias(TSecondClass, '2');
function Factory(ClassId: Integer; Param: SomeType): TMyObject;
var
ClassType: TMyClass;
begin
ClassType := TMyClass(FindClass(IntToStr(ClassId)));
Result := ClassType.Create(Param);
end;
Тут мы воспользовались стандартным реестром классов, занеся в него элементы с помощью вызовов RegisterClassAlias. Ограничение этого реестра в том, что регистрировать в нем можно только потомки TPersistent. Если ваши классы не являются его потомками, то можно реализовать свой простенький реестр, на основе, скажем, TStringList
2 comments:
иногда такой подход более, чем оправдан:)
одно-два ветвления вместо добавления нескольких классов и/или конструкторов.
Спасибо!
уже неделю мучаюсь в поисках подобного решения.
и главное знал же, но как пользовать - не дошел)
Post a Comment