在Delphi中创建自身实例的类函数

MX4*_*399 7 delphi design-patterns delphi-xe

你有一个类函数可以创建一个类的实例:

TMyClass = class(TSomeParent)
public
  class function New(AValue : integer) : TMyClass; 
end;

TDerivedClass = class(TMyClass)
public
  function Beep;
end;
Run Code Online (Sandbox Code Playgroud)

然后按如下方式使用它

...   
var
  myList : TList<T>;
  item : TDerivedClass;
begin
  myList.Add(TDerivedClass.New(1))
  myList.Add(TDerivedClass.New(3))
  myList.Add(TDerivedClass.New(5))

  for item in myList do
    item.Beep; //times the count in the class function
...
Run Code Online (Sandbox Code Playgroud)

如果是这样,那个功能代码是什么样的?您是否使用TObject的NewInstance方法并且每次为每个派生类重新实现?使用构造函数是否更安全/更好?

目标是在命令模式中使用此方法并使用类类型和接收器加载命令列表,例如:

//FYI: document is an instance of TDocument
commandList.Execute(TOpenDocument(document)); 
commandList.Execute(TPasteFromClipboard(document)); 
//... lots of actions - some can undo
commandList.Execute(TPrintDocument(document)); 
commandList.Execute(TSaveDocument(document));
Run Code Online (Sandbox Code Playgroud)

原因是某些命令将通过text/script指定,需要在运行时解析.

Mas*_*ler 12

您正在寻找的是工厂模式.它可以在Delphi中完成; 它是VCL如何反序列化形式等等.您缺少的是系统的注册/查找部分.这是基本的想法:

  • 某处,你设置了一个注册表.如果您使用的是Delphi XE,则可以将其实现为a TDictionary<string, TMyClassType>,其中TMyClassType定义为class of TMyClass.这个很重要.您需要类名和类类型引用之间的映射.
  • 在TMyClass上放置一个虚拟构造函数.当工厂模式创建它时,从它下降的所有内容都将使用此构造函数或覆盖它.
  • 创建新的后代类时,让它调用一个方法,该方法将自己注册到注册表.这应该在程序启动时发生,无论是在初始化还是在类构造函数中.

当您需要从脚本中实例化某些内容时,请执行以下操作:

 class function TMyClass.New(clsname: string; [other params]): TMyClass;
 begin
   result := RegistrationTable[clsName].Create(other params);
 end;
Run Code Online (Sandbox Code Playgroud)

您可以使用注册表从类名中获取类引用,并在类引用上调用虚拟构造函数以从中获取正确类型的对象.


Rem*_*eau 5

是的,技术上可以从类方法创建实例,只需调用实际的构造函数然后返回它创建的实例,例如:

type
  TMyClass = class(TSomeParent)
  public
    constructor Create(AValue : Integer); virtual;
    class function New(AValue : integer) : TMyClass;
  end;

  TDerivedClass = class(TMyClass)
  public
    constructor Create(AValue : Integer); override;
    function Beep;
  end;

constructor TMyClass.Create(AValue : Integer);
begin
  inherited Create;
  ...
end;

function TMyClass.New(AValue : integer) : TMyClass;
begin
  Result := Create(AValue);
end;

constructor TDerivedClass.Create(AValue : Integer);
begin
  inherited Create(AValue);
  ...
end;

var
  myList : TList<TMyClass>;
  item : TMyClass;
begin
  myList.Add(TDerivedClass.New(1))
  myList.Add(TDerivedClass.New(3))
  myList.Add(TDerivedClass.New(5))
  for item in myList do
    TDerivedClass(item).Beep;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您最好直接使用构造函数:

type
  TMyClass = class(TSomeParent)
  end;

  TDerivedClass = class(TMyClass)
  public
    constructor Create(AValue : Integer);
    function Beep;
  end;

var
  myList : TList<TDerivedClass>;
  item : TDerivedClass;
begin
  myList.Add(TDerivedClass.Create(1))
  myList.Add(TDerivedClass.Create(3))
  myList.Add(TDerivedClass.Create(5))
  for item in myList do
    item.Beep;
Run Code Online (Sandbox Code Playgroud)


dma*_*kic 2

你能有一个类函数来创建类的实例吗?
使用构造函数是否更省/更好?

构造函数是创建类实例的类函数。只需输入:

constructor New(); virtual;
Run Code Online (Sandbox Code Playgroud)

你就可以走了。

virtual;部分将允许您为所有后代类调用相同的 New() 构造函数。