2011-03-30 95 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