2010-10-28 20 views
20

Jakie są plusy i minusy powielania instancji obiektu z funkcją konstruktora lub instancji?Poprawny sposób duplikowania obiektu Delphi

Przykład 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; 

Przykład 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; 

Główną różnicą bezpośrednio do głowy - w tym drugim przypadku, konstruktor Tworzenie musiałby być wirtualnej, które hierarchii klas wspierania Klon mógł zostać zbudowany na bazie TMyObject.

Załóżmy, że to nie jest problem - że TMyObject i wszystko na nim oparte jest całkowicie pod moją kontrolą. Jaki jest twój preferowany sposób tworzenia konstruktora kopiowania w Delphi? Którą wersję uważasz za bardziej czytelną? Kiedy używałbyś poprzedniego lub drugiego podejścia? Omawiać. :)

EDIT: Moim głównym problemem z pierwszym przykładzie jest to, że zastosowanie jest bardzo ciężki w porównaniu do drugiego podejścia, tj

newObj := TMyObject.Create(oldObj) 

vs.

newObj := oldObj.Clone; 

EDIT2 lub „Dlaczego Chcę działać w trybie jednokierunkowym "

Zgadzam się, że w większości przypadków funkcja przypisania jest rozsądnym podejściem. Jest nawet rozsądne implementowanie "konstruktora kopii" wewnętrznie, po prostu używając assign.

Zazwyczaj tworzę takie kopie podczas wielowątkowości i przekazywania obiektów przez kolejkę komunikatów. Jeśli tworzenie obiektów jest szybkie, zwykle przekazuję kopię oryginalnego obiektu, ponieważ to naprawdę upraszcza problem własności obiektu.

IOW, wolę pisać

Send(TMyObject.Create(obj)); 

lub

Send(obj.Clone); 

do

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

Odpowiedz

24

Pierwszy dodaje informacje o który obiekt chce tworzyć, a drugie nie. Można to wykorzystać do utworzenia instancji np. potomkiem lub przodkiem klasy

The sposób Delphi (TPersistent) oddziela tworzenie i klonowanie:

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

i ma tę samą właściwość, która jawnie wybrać klasę instancji. Ale nie potrzebujesz dwóch konstruktorów, jednego do normalnego użytku i jednego, który chcesz sklonować.

edit powodu oneline wymogu Można mieszać go oczywiście używając metaclasses Delphi (niesprawdzone)

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 

do reszty, tylko realizować swoje operatorów assign() i można mieszać różne sposoby.

Edit2

I otrzymuje się powyższy kod z kodem badanego w D2009. Istnieją pewne zależności między typami, które mogły cię zdezorientować, mam nadzieję, że w ten sposób będą jaśniejsze. Oczywiście będziesz musiał przestudiować mechanizm przypisania. Przetestowałem również domyślny parametr metaclass=nil i działa, więc dodałem go.

+1

Głosowałbym za twoją odpowiedzią, ale to zniszczyłoby twój 5,555 wynik. ;-) Gratulacje! – splash

+3

Cóż, chcę osiągnąć 6666 jeden dzień :-) –

+0

OK, proszę bardzo! +1 – splash

6

Nie sądzę, że istnieje poprawny sposób, że zależy to tylko od osobistego stylu. (Jak zauważył Marco, jest więcej sposobów.)

  • Sposób konstruktora jest krótki, ale narusza zasadę, że konstruktor musi tylko konstruować obiekt. Który prawdopodobnie nie stanowi problemu.
  • Sposób klonowania jest krótki, chociaż trzeba podać wezwanie dla każdej klasy.
  • Sposób przypisania jest bardziej podobny do Delphi. Oddziela tworzenie i inicjalizację, co jest dobre, ponieważ podoba nam się koncepcja jednej metody, która sprawia, że ​​kod jest lepszy w utrzymaniu.

A jeśli zaimplementujesz Przypisywanie za pomocą strumieni, masz tylko jedno miejsce do obaw o to, które pola muszą być dostępne.

3

Lubię styl klonu - ale tylko w Javie (lub innym języku GC). Używałem go czasami w Delphi, ale najczęściej przebywam z Create i Assign, ponieważ jest o wiele jaśniejsze, kto jest odpowiedzialny za zniszczenie obiektu.

+2

Generalnie nienawidzę używając konstruktorów z argumentami. Kiedy zaczynasz komplikować swój framework, zaczyna on gryźć cię w

+1

Naprawdę lubię konstruktory wymuszające przekazywanie wszystkich niezbędnych obiektów, takich jak 'Create (AOwner)'.Szkielety zastrzyków zależnych znają oba smaki, zastrzyk zależności oparty na właściwościach lub konstruktorze - oba mają swoje zalety (i przeciw). – mjn

+0

@Rjustin: ja też, ale zazwyczaj nie używam konstruktorów do tworzenia kopii. – splash

Powiązane problemy