Question

i have a list of class instances of various kinds. i need to be able to create a new instance of a class without knowing for sure what to create. all the objects involved have the same ancestor. the actual copying of the object's member variables is easy...it's the creation of the new object where i have a problem.

admittedly i could do something like this:

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

  obj2:
    Result:=TObjectType2.Create;

  obj3:
    Result:=TObjectType3.Create;
end;

that wouldn't follow the "open/closed principle".

initially i thought i could do something like "Result:=MyObjectTypeInstance.Create;" but that didn't work as hoped because of destructor difficulties.

here's the latest guess how i should be doing this...

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;

i would've thought this'd be easier!

thank you for your help!

Was it helpful?

Solution

You will probably want to create an Abstract Factory or Factory Method class. These are common Design Patterns which are tested, proven development paradigms.

OTHER TIPS

If all classes have a common ancestor, you can do something like this:

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;

You can use any kind of identification for the type registration. As long as they are unique.

Option 1 - create a list of name/class mappings: Is there a way to instantiate a class by its name in delphi?

Option 2 - use a 'of class' variable.

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

thank you all for your answers!

dar7yl's solution suited my needs perfectly.

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;

Another, messier version is using "class of type" and 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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top