2010-10-28 50 views
20

¿Cuáles son los pros y los contras de la duplicación de una instancia de objeto con el constructor o la función de instancia?Forma correcta de duplicar el objeto Delphi

Ejemplo 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; 

Ejemplo 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; 

Una gran diferencia de inmediato viene a la mente - en este último caso el constructor Crear tendría que ser virtual para que una jerarquía de clases de apoyo El clon podría construirse basándose en el TMyObject.

Supongamos que esto no es un problema, que TMyObject y todo lo que se basa en él está completamente bajo mi control. ¿Cuál es tu forma preferida de hacer copy constructor en Delphi? ¿Qué versión encuentras más legible? ¿Cuándo utilizarías el enfoque anterior o posterior? Discutir. :)

EDIT: Mi principal preocupación con el primer ejemplo es que el uso es muy pesada en comparación con el segundo enfoque, es decir

newObj := TMyObject.Create(oldObj) 

vs

newObj := oldObj.Clone; 

Edit2 o "¿Por qué Deseo una operación de línea única "

Acepto que Assign es un enfoque razonable en la mayoría de los casos. Incluso es razonable implementar 'constructor de copia' internamente simplemente usando assign.

Por lo general, creo esas copias cuando multiprocesamiento y paso de objetos a través de la cola de mensajes. Si la creación de objetos es rápida, por lo general paso una copia del objeto original porque eso realmente simplifica los problemas de propiedad del objeto.

OIA, yo prefiero escribir

Send(TMyObject.Create(obj)); 

o

Send(obj.Clone); 

a

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

Respuesta

24

La primera añade información sobre cuál es el objeto que desee crear, el segundo no. Esto se puede usar para crear instancias, p. un descendiente o un ancestro de una clase

La forma en Delphi (TPersistent) separa la creación y la clonación:

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

y tiene la misma propiedad que se especifica explícitamente que la clase a instanciar. Pero no necesita dos constructores, uno para uso normal y otro para clonar.

edición debido a la exigencia oneline Se puede mezclar, por supuesto, el uso de metaclases Delphi (no probados)

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 

Por lo demás, simplemente poner en práctica sus assign() operadores, y se puede mezclar varias maneras.

Edit2

I sustituye el código anterior con el código de prueba en D2009. Hay algunas dependencias de los tipos que podrían haberlo confundido, espero que sea más claro de esta manera. Por supuesto, tendrás que estudiar el mecanismo de asignación. También probé el parámetro predeterminado metaclass=nil y funciona, así que lo agregué.

+1

Yo votaría por su respuesta, pero esto destruiría su puntaje de 5.555. ;-) ¡Felicitaciones! – splash

+3

Bueno, quiero llegar a 6666 un día :-) –

+0

OK, aquí tienes! +1 – splash

6

No creo que exista una forma correcta de que solo dependa del estilo personal. (Y como Marco señaló, hay más formas).

  • La forma del constructor es corta, pero viola el principio de que el constructor solo debe construir el objeto. Lo cual posiblemente no sea un problema.
  • El modo clon es corto, aunque debe proporcionar una llamada para cada clase.
  • La forma de asignación es más como Delphi. Separa la creación y la inicialización, lo que es bueno porque nos gusta el método de un concepto de función que hace que el código sea mejor de mantener.

Y si implementa Asignar utilizando transmisiones, solo tiene un lugar donde preocuparse sobre qué campos deben estar disponibles.

3

Me gusta el clon estilo, pero solo en Java (o en cualquier otro lenguaje de GC). Lo usé algunas veces en Delphi, pero sobre todo me quedo con Create y Assign, porque está mucho más claro quién es responsable de la destrucción del objeto.

+2

En general odio usar constructores con argumentos. Cuando empiezas a hacer tu marco más complicado, comienza a morderte en el

+1

Me gustan mucho los constructores que hacen cumplir el paso de todos los objetos necesarios, como 'Create (AOwner)'.Los marcos de inyección de dependencia saben que ambos sabores, la inyección de dependencia basada en la propiedad o el constructor, tienen sus pros (y sus contras). – mjn

+0

@mjustin: yo también, pero generalmente no uso constructores para crear una copia. – splash

Cuestiones relacionadas