2011-03-30 97 views
4

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

谢谢。

回答

6

没有内置任何东西可以为您执行深层克隆。我相信你可以根据新的RTTI编写一个深层克隆,但我认为这是一个不重要的工作量。

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

  • 对象的一些群体需要按照特定的顺序被创建。
  • 某个类的某些成员不应该被克隆,例如,参考计数。你如何识别RTTI?
  • 你如何处理单身?
  • 需要设置什么外在引用?假设你克隆了一个通常由工厂创建的对象。如果该工厂对其创建的对象持有引用,那么背后可能会破坏您的设计。

你可以通过定义使用RTTI简单的类型,然后你必须覆盖它的任何东西更复杂的一个基本Clone()方法实现的原型模式。虽然个人,我会从TPersistent继承,并根据AssignClone()方法。

+0

我能做些什么,如果我使用D2007?我想克隆()在2007版本中不可用? – elector 2011-03-30 10:53:54

+0

@elector克隆是您自己编写的函数。这就是Prototype的本质。如果你有一个更新的Delphi,那么RTTI可以提供帮助,但是在2007年你肯定会自己去做。 – 2011-03-30 10:55:30

+0

或者您建议为D2007分配TPersistent?这是一个很好的Prototype模式实现的例子吗? 编辑:我刚才看到你对我以前的问题的答案。谢谢 – elector 2011-03-30 10:59:44

8

Object.MemberwiseClone Method使该对象的副本遵循一些非常简单的规则,并利用.NET垃圾收集器的工作原理。

  • 参考文件被简单复制。这包括任何object的字符串和引用。
  • 值类型比特复制(相同的克隆。制造)。

有关值类型的部分可以很容易地用Delphi复制。使用Delphi复制引用类型的行为,虽然在技术上很简单,但不会提供预期的结果:Delphi代码预计会创建它的对象,并使用owner-owned范例来确保发生。通常的模式是从析构函数中释放由拥有者对象创建的对象。如果您制作对象的Shalow-copy,则会导致失败。这里有一个例子:

  • 对象A拥有一个参考对象B.
  • 我们创建对象C的对象A.对象的浅表副本C现在包含一个参考对象B.
  • 我们免费对象A:A.Free;
  • 我们免费对象B:B.Free; - 这会自动调用B.Free,但不幸的是,当我们释放A B已经被释放!

我们可以尝试deep-copy,大卫建议,但提出了一些同样的难题:

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

把这一切放在一起,我们只能得出一个结论:我们不能有一个通用的,德尔福相当于MemberwiseClone。我们可以通过简单的交互来获得简单对象的部分外观,但这几乎没有吸引力!

+0

我们假设我们正在讨论原型模式的具体用法,而不是通用模式。我们需要深入复制一个自定义的,但已知的对象。我猜这种模式的目的是加速创建许多对象,对吗?我们知道这些将是什么对象。考虑到这一切,在Delphi中有什么好的解决方案?使用内存流,序列化......?而不是在原型对象中使用已发布的属性。 – elector 2011-03-30 11:33:42

+0

@elector,我需要克隆的Delphi 7对象实际上提供了一个返回对象副本的'Duplicate'方法; 'Duplicate'方法通常是手工实现的(按字段分配),但我有一些依赖某些流式代码的实现。流媒体代码本身是手写的(逐场),我的“Duplicate”仅使用流媒体,因为我的懒惰:逐字段手拷的速度会更快。 – 2011-03-30 11:39:39

+0

通过字段分配方法,原型模式是否有意义?我们是否能更快地创建大量的对象?我猜想流媒体代码不会更快地创建对象吗? – elector 2011-03-30 12:04:21

1

我发布了一个稍微通用的component cloning回答,虽然它不等于MemberWiseClone,但可能有用。它在Delphi中的工作早在D5,我相信,并且我相信它在D2007中起作用。

3

有一种方法可以在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; 
+0

不错!但我想如果对象包含一个具有循环对象引用的集合,它将不起作用? – mjn 2012-02-08 16:37:06

+0

它确实与集合一起工作。我用一个包含通用TList 和其他对象字段的基础测试它。有效! – Yanniel 2012-02-10 15:54:00

+0

这会引发错误“内部:类型tkPointer当前不受支持”,我在XE上并且有复杂的对象来进行深度复制。 – Alex 2013-04-26 15:40:07