Как я могу создать новый экземпляр класса? - PullRequest
1 голос
/ 16 апреля 2009

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

по общему признанию я мог сделать что-то подобное:

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

  obj2:
    Result:=TObjectType2.Create;

  obj3:
    Result:=TObjectType3.Create;
end;

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

Первоначально я думал, что могу сделать что-то вроде "Result: = 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;

Я бы подумал, что это будет проще!

спасибо за помощь!

Ответы [ 5 ]

11 голосов
/ 16 апреля 2009

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

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;

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

8 голосов
/ 16 апреля 2009

Вариант 1 - создать список сопоставлений имен / классов: Есть ли способ создания экземпляра класса по его имени в 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
4 голосов
/ 16 апреля 2009

Возможно, вы захотите создать класс Abstract Factory или Factory Method. Это общие шаблоны проектирования , которые являются проверенными, проверенными парадигмами разработки.

2 голосов
/ 17 апреля 2009

Другая, более сложная версия использует "класс типа" и 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;
2 голосов
/ 16 апреля 2009

спасибо всем за ответы!

Решение

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;
...