delphi原型模式

时间:2011-03-30 09:57:53

标签: delphi design-patterns delphi-2007 prototype-pattern

我想知道,Delphi的RTTI中是否有与MemberwiseClone在C#中执行相同操作的原型模式的简单实现。 我看到了这个模式的一些Delphi实现,其中正在创建一个新对象(TMyObject.Create),并且它的属性使用原型对象的值进行分配。我可能错了,但如果我们以相同的基本方式创建对象,我看不到模式的好处。

谢谢。

5 个答案:

答案 0 :(得分:9)

Object.MemberwiseClone Method根据一些非常简单的规则生成对象的副本,并利用.NET垃圾收集器的工作方式。

  • 简单地复制参考文献。这包括字符串和对任何object
  • 的引用
  • 值类型是位复制的(制作相同的克隆)。

有关值类型的部分可以使用Delphi轻松复制。使用Delphi复制引用类型行为虽然技术上很简单,但不会提供预期的结果:Delphi代码需要.free它创建的对象,它使用owner-owned范例来确保发生这种情况。通常的模式是释放由析构函数中的owner-object创建的对象。如果您制作对象的shalow副本,则会导致失败。这是一个例子:

  • 对象A拥有对象B的引用。
  • 我们将对象C创建为对象A的浅表副本。对象C现在包含对对象B的引用。
  • 我们释放对象A:A.Free;
  • 我们释放对象B:B.Free; - 这会自动调用B.Free,但不幸的是,当我们释放A时,B已经被释放了!

我们可以像大卫建议的那样尝试deep-copy,但这会带来一些同样困难的问题:

  • 并非所有对象都应该被复制,例如因为它们封装了对真实世界资源的引用(例如:TFileStream)。
  • 其他一些物品不能被深层复制,因为它们是单身的。并且没有通用的方式说“这个对象是一个单例,做一个简单的引用副本,不要做深度复制”。示例:我们是否复制Application
  • 如果你做了深层复制,你可能有循环引用,你需要照顾那些。这不是微不足道的,你从一个集合中的一个项目开始复制,你可能会发现自己回到了你的集合的父级,即:不完全是预期的结果。
  • 不加区分的深层处理可能会占用意外的内存量并导致意外的内存泄漏。想想收藏 - > item - >再次复制项目示例,您最终获得了“项目”的副本,但由于意外的反向链接而复制了整个COLLECTION。

把这些全部放在一起我们只能得出一个结论:我们不能有一般的目的,相当于MemberwiseClone的Delphi。对于具有简单交互的简单对象,我们可以有类似的外观,但这并不是那么有吸引力!

答案 1 :(得分:6)

没有任何内置功能可以为您执行深度克隆。我相信你可以根据新的RTTI编写一个深度克隆,但我希望它是一项非常重要的工作。

如果您处理的是足够简单的类型,它可以正常工作,但您很容易遇到严峻的挑战。例如,在我的头顶:

  • 需要按特定顺序创建某些对象组。
  • 不应克隆某类成员,例如参考计数。你怎么认识那些有RTTI的人?
  • 你如何对待单身人士?
  • 需要设置的任何外在参考怎么样?假设您克隆了通常由工厂创建的对象。如果该工厂拥有对其创建的对象的引用,那么它背后可能会破坏您的设计。

您可以通过定义一个基本Clone()方法来实现原型模式,该方法将RTTI用于简单类型,然后您必须覆盖它以获得更复杂的东西。就个人而言,我会继承TPersistent并根据Clone()生成Assign方法。

答案 2 :(得分:4)

有一种方法可以在Delphi中执行对象的深层复制(克隆)。它适用于最新版本的Delphi(2010及以上版本)。看下面剪下的代码......它实际上很简单,你不需要外部库。您可以在此处找到更多信息:http://www.yanniel.info/2012/02/deep-copy-clone-object-delphi.html

function DeepCopy(aValue: TObject): TObject;
var
  MarshalObj: TJSONMarshal;
  UnMarshalObj: TJSONUnMarshal;
  JSONValue: TJSONValue;
begin
  Result:= nil;
  MarshalObj := TJSONMarshal.Create;
  UnMarshalObj := TJSONUnMarshal.Create;
  try
    JSONValue := MarshalObj.Marshal(aValue);
    try
      if Assigned(JSONValue) then
        Result:= UnMarshalObj.Unmarshal(JSONValue);
    finally
      JSONValue.Free;
    end;
  finally
    MarshalObj.Free;
    UnMarshalObj.Free;
  end;
end;

答案 3 :(得分:1)

我认为你正在寻找类似的东西:http://code.google.com/p/delphilhlplib/source/browse/trunk/Library/src/Extensions/DeHL.Cloning.pas

它仅适用于D2010及以上版本(需要扩展RTTI)。

答案 4 :(得分:1)

我前一段时间发布了一个有点通用的component cloning回答可能有用,虽然它不等同于MemberWiseClone。早在D5,它就可以在Delphi中运行,我相信,我相信它在D2007中有效。