2009-04-16 7 views
1

У меня есть список экземпляров классов различных типов. Мне нужно создать новый экземпляр класса, не зная наверняка, что создавать. все задействованные объекты имеют одного и того же предка. фактическое копирование переменных-членов объекта легко ... это создание нового объекта, в котором у меня проблема.Как создать новый экземпляр класса?

правда я мог бы сделать что-то вроде этого:

case MyObjectTypeInstance.MyTypeEnum of 
    obj1: 
    Result:=TObjectType1.Create; 

    obj2: 
    Result:=TObjectType2.Create; 

    obj3: 
    Result:=TObjectType3.Create; 
end; 

, что не будет следовать «открытый/закрытый принцип».

Первоначально я думал, что могу сделать что-то вроде «Результат: = MyObjectTypeInstance.Create;» но это не так надеялось из-за трудностей деструктора.

вот последнее предположение, как я должен делать это ...

var 
    fooA, fooB:TFoo; 
begin 
    fooA:=TFoo2.Create; // it could be any of many types 

    fooB:=? // how to create fooB of same class type as fooA???? 

    // do something 

    fooA.Free; 
    fooB.Free; 
end; 

я бы мог подумать this'd быть проще!

Благодарим за помощь!

ответ

4

Возможно, вы захотите создать класс абстрактных фабричных или заводских методов. Они являются общими Design Patterns, которые являются проверенными, проверенными парадигмами развития.

+0

да ... конечно! я должен был подумать об этом! Спасибо! –

8

Вариант 1 - создать список отображений/имя класса: Is there a way to instantiate a class by its name in delphi?

Вариант 2 - использовать 'класса' переменной.

type 
    TBaseObj = class 
    end; 

    TObjA = class(TBaseObj) 
    end; 

    TBaseObjClass = class of TBaseObj; 

var 
    objCls: TBaseObjClass; 
    obj: TBaseObj; 

objCls := TObjA; 
obj := objCls.Create; 
//obj is of type TObjA 
+1

спасибо Gabr! на самом деле, спасибо за ваш огромный вклад в StackOverflow. –

11

Если все классы имеют общего предка, вы можете сделать что-то вроде этого:

type 
    TAncestor = class; 
    TAncestorClass = class of TAncestor; 
    TAncestor = class 
    public 
    constructor Create; virtual; 

    class function CreateClass(const AId: string): TAncestor; 
    class procedure RegisterClass(const AId: string; const AType: TAncestorClass); 
    end; 


class function TAncestor.CreateClass(const AId: string): TAncestor; 
var 
    atype : TAncestorClass; 
begin 
    atype := GetAncestorClass(AId); 
    if atype<>nil then 
    Result := atype.Create 
    else 
    Result := nil; 
end; 

class procedure TAncestor.RegisterClass(const AId: string; 
    const AType: TAncestorClass); 
begin 
    SetAncestorClass(AId, AType); // Link id to class type 
end; 

Вы можете использовать любой вид идентификации для регистрации типа. Пока они уникальны.

+0

спасибо Gamecat! на самом деле, спасибо за ваш огромный вклад в StackOverflow. –

+1

Эй, мы в нем вместе ;-). Но спасибо. –

2

благодарит всех вас за ответы!

Решение dar7yl идеально подходит для моих потребностей.

type 
    TFoo = class 
    private 
    { private declarations } 
    public 
    { public declarations } 
    class function MakeAnother:TFoo; 
    end; 

    TFoo1 = class(TFoo) 
    private 
    { private declarations } 
    public 
    { public declarations } 
    end; 

    TFoo2 = class(TFoo) 
    private 
    { private declarations } 
    public 
    { public declarations } 
    end; 

var 
    fooA, fooB:TFoo; 
begin 
    fooA:=TFoo2.Create; 
    foob:=fooA.MakeAnother; 

    // do something here 

    fooA.Free; 
    fooB.Free; 
end; 

{ TFoo } 

class function TFoo.MakeAnother: TFoo; 
begin 
    Result:=Create; 
end; 
+0

Спасибо, что разместили это дополнение к вашему вопросу/примеру - очень полезно для «lurkers» и «laters» с похожими вопросами ». :) – Jamo

+0

добро пожаловать. я всегда благодарен, что вижу подобные действия, поэтому я стараюсь делать это сам! –

+0

спасибо за пример кода. – avar

2

Другие, хаотичная версия использует "класс типа" и TObject.ClassType

type 
TFoo = class 
    private 
    { private declarations } 
    public 
    { public declarations } 
    constructor Create(WhatEver : Integer);virtual;// just to show need for params 
    end; 

    TFooClass = class of TFoo; 

    TFoo1 = class(TFoo) 
    private 
    { private declarations } 
    public 
    { public declarations } 
    constructor Create(WhatEver : Integer);override;// just to show need for params 
    end; 

    TFoo2 = class(TFoo) 
    private 
    { private declarations } 
    public 
    { public declarations } 
    end; 


{$R *.dfm} 

procedure TForm10.Button1Click(Sender: TObject); 
var 
    fooA, fooB:TFoo; 

begin 
    fooA:=TFoo2.Create(0); 
    fooB:= TFooClass(FooA.ClassType).Create(1); 

    // do something here 

    fooA.Free; 
    fooB.Free; 

end; 

{ TFoo } 

constructor TFoo.Create(WhatEver: Integer); 
begin 
    ShowMessageFmt('%s %d', [Self.ClassName, WhatEver]); 
end; 

{ TFoo1 } 

constructor TFoo1.Create(WhatEver: Integer); 
begin 
    inherited; 

end; 
+0

Не назвал бы это беспорядочным, но довольно гибким :) Недавно я использовал его для создания функций clone, где базовый класс может создать правильный экземпляр дочернего класса. –

+0

Я думаю, что это настоящий путь Delphi **. Просто убедитесь, что конструкторы виртуальны. Обратите внимание, что причина, по которой вам приходится писать TFooClass (FooA.ClassType). Создавать вместо FooA.Create это то, что последнее не будет выделять новый объект - так Delphi называет унаследованные конструкторы! –

Смежные вопросы