2010-10-28 41 views
20

复制带构造函数或实例函数的对象实例有什么优点和缺点?正确的复制Delphi对象的方法

实施例A:

type 
    TMyObject = class 
    strict private 
    FField: integer; 
    public 
    constructor Create(srcObj: TMyObject); overload; 
    //alternatively: 
    //constructor CreateFrom(srcObj: TMyObject); 
    property Field: integer read FField; 
    end; 

constructor TMyObject.Create(srcObj: TMyObject); 
begin 
    inherited Create; 
    FField := srcObj.Field; 
end; 

实施例B:

type 
    TMyObject = class 
    strict private 
    FField: integer; 
    public 
    function Clone: TMyObject; 
    property Field: integer read FField; 
    end; 

function TMyObject.Clone: TMyObject; 
begin 
    Result := TMyObject.Create; 
    Result.FField := FField; 
end; 

一个主要区别立即弹簧想到 - 在后一种情况下,创建的构造将具有使得一个类层次结构支撑是虚拟克隆可以基于TMyObject构建。

假设这不是一个问题 - TMyObject和基于它的所有东西完全在我的控制之下。在Delphi中做复制构造函数的首选方法是什么?你觉得哪个版本更具可读性?你什么时候会使用前一种或后一种方法?讨论。 :)

编辑: 我与第一个例子主要关注的是,相对于第二种方法的使用是非常沉重的,即

newObj := TMyObject.Create(oldObj) 

newObj := oldObj.Clone; 

EDIT2或“为什么我想单线操作“

我同意Assign在大多数情况下是合理的方法。通过简单地使用assign,在内部实现“拷贝构造函数”甚至是合理的。

我通常在多线程和通过消息队列传递对象时创建这样的副本。如果对象创建速度很快,我通常会传递原始对象的副本,因为这样可以真正简化对象所有权的问题。

IOW,我喜欢写

Send(TMyObject.Create(obj)); 

Send(obj.Clone); 

newObj := TMyObject.Create; 
newObj.Assign(obj); 
Send(newObj); 

回答

24

首先增加了约哪个对象要创建,第二个不行信息。这可以用来实例化例如后代或一类

德尔菲方法(TPersistent)的祖先创造分离和克隆:

dest := TSomeClass.Create; 
dest.Assign(source); 

,并具有您明确选择的类实例化这个相同的属性。但是,您不需要两个构造函数,一个用于正常使用,另一个用于您想要克隆的构造函数。

编辑由于ONELINE要求 您可以用Delphi元类(未经测试)当然混用

type 
    TBaseSomeObject = class; 
    TBaseObjectClass = class of TBaseSomeObject; 

    TBaseSomeObject = class(TPersistent) 
    function Clone(t: TBaseObjectClass = nil): TBaseSomeObject; virtual; 
    end; 

... 

    function TBaseSomeObject.Clone(t: TBaseObjectClass = nil): TBaseSomeObject; 
    begin 
    if Assigned(t) then 
     Result := t.Create 
    else 
     Result := TBaseObjectClass(Self.ClassType).Create; 
    Result.Assign(Self); 
    end; 


SendObject(obj.Clone); // full clone. 
SendObject(obj.Clone(TDescandantObject)); // Cloned into Descendant object 

对于剩下的,只是实现你assign()运营商,你可以混合多种方式。

EDIT2

我取代上面在D2009测试的代码的代码。有些类型的依赖关系可能会让你感到困惑,希望这种方式更清晰。当然,你必须研究分配机制。我也测试了metaclass=nil默认参数,它工作,所以我加了它。

+1

我会为你的答案投票,但这会破坏你的5,555分。 ;-) 恭喜! – splash 2010-10-28 11:16:04

+3

嗯,我确实想要有一天达到6666 :-) – 2010-10-28 11:24:13

+0

好的,在这里你走! +1 – splash 2010-10-28 11:53:25

6

我不认为有一个正确的方式,它只是取决于个人风格。 (正如Marco指出的那样,有更多的方法。)

  • 构造函数的方法很简短,但它违反了构造函数只能构造对象的原则。这可能不是问题。
  • 虽然您需要为每个班级提供电话,但克隆方式很短。
  • 分配方式更像Delphi。它将创建和初始化分开,这是很好的,因为我们喜欢使代码更好维护的一种方法或一种功能概念。

如果您使用流实现Assign,则只有一个地方可以担心哪些字段需要可用。

3

我喜欢克隆样式 - 但仅限于Java(或任何其他GC语言)。我在德尔福使用过它,但大多数时候我在CreateAssign中呆过,因为它更清楚谁负责破坏对象。

+2

我通常讨厌使用带参数的构造函数。当你开始让你的框架变得更复杂的时候,它开始咬你 2010-10-28 11:25:24

+1

我真的很喜欢强制传递所有必要对象的构造函数,比如'Create(AOwner)'。依赖注入框架知道两种风格,基于Property或Constructor的依赖注入 - 都有其优点(和缺点)。 – mjn 2010-10-28 12:07:00

+0

@mjustin:我也是,但我通常不使用构造函数来创建副本。 – splash 2010-10-28 12:20:06

相关问题