2010-10-28 26 views
20

Ưu và khuyết điểm của sao chép một đối tượng đối tượng với hàm tạo hoặc hàm mẫu là gì?Cách chính xác để nhân đôi đối tượng Delphi

Ví dụ 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; 

Ví dụ 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; 

Một khác biệt lớn ngay lập tức lò xo để tâm trí - trong trường hợp này các nhà xây dựng Tạo sẽ phải ảo để một hệ thống phân cấp lớp hỗ trợ Bản sao có thể được xây dựng dựa trên TMyObject.

Giả sử đây không phải là vấn đề - TMyObject và mọi thứ dựa trên nó hoàn toàn nằm trong tầm kiểm soát của tôi. Cách ưa thích của bạn làm bản sao constructor trong Delphi là gì? Phiên bản nào bạn thấy dễ đọc hơn? Khi nào bạn sử dụng phương pháp tiếp cận cũ hoặc sau? Bàn luận. :)

EDIT: mối quan tâm chính của tôi với ví dụ đầu tiên là việc sử dụng là rất nặng so với phương pháp thứ hai, tức là

newObj := TMyObject.Create(oldObj) 

vs

newObj := oldObj.Clone; 

EDIT2 hoặc "Tại sao Tôi muốn hoạt động một dòng "

Tôi đồng ý rằng Chỉ định là phương pháp hợp lý trong hầu hết các trường hợp. Nó thậm chí còn hợp lý để thực hiện 'copy constructor' nội bộ đơn giản bằng cách sử dụng gán.

Tôi thường tạo các bản sao như vậy khi đa luồng và truyền các đối tượng thông qua hàng đợi tin nhắn. Nếu tạo đối tượng nhanh, tôi thường chuyển một bản sao của đối tượng gốc vì nó thực sự đơn giản hóa các vấn đề về quyền sở hữu đối tượng.

IOW, tôi thích viết

Send(TMyObject.Create(obj)); 

hoặc

Send(obj.Clone); 

để

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

Trả lời

24

Đầu tiên cho biết thêm thông tin về những đối tượng muốn tạo, thứ hai không. Điều này có thể được sử dụng để khởi tạo ví dụ: một hậu duệ hoặc tổ tiên của một lớp

Các Delphi chiều (TPersistent) tách sáng tạo và nhân bản:

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

và có thuộc tính này tương tự mà bạn chắc chắn chọn lớp để nhanh chóng. Nhưng bạn không cần hai nhà xây dựng, một cho sử dụng bình thường, và một nơi bạn muốn sao chép.

chỉnh sửa do oneline yêu cầu Bạn có thể kết hợp nó dĩ nhiên sử dụng Delphi metaclasses (chưa được kiểm tra)

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 

Đối với phần còn lại, chỉ cần thực hiện assign() nhà khai thác của bạn, và bạn có thể kết hợp nhiều cách khác nhau.

edit2

Tôi thay thế các mã trên với mã thử nghiệm trên D2009. Có một số phụ thuộc của các loại có thể đã nhầm lẫn bạn, hy vọng nó là rõ ràng hơn theo cách này. Tất nhiên bạn sẽ phải nghiên cứu cơ chế chỉ định. Tôi cũng đã thử nghiệm tham số mặc định metaclass=nil và nó hoạt động, vì vậy tôi đã thêm nó.

+1

Tôi sẽ bỏ phiếu cho câu trả lời của bạn, nhưng điều này sẽ phá hủy số điểm 5,555 của bạn. ;-) Chúc mừng! – splash

+3

Vâng, tôi muốn đạt 6666 một ngày :-) –

+0

OK, thông tin cho bạn đây! +1 – splash

6

Tôi không nghĩ rằng đó là một cách chính xác nó chỉ phụ thuộc vào phong cách cá nhân. (Và như Marco đã chỉ ra, có nhiều cách hơn.)

  • Cách xây dựng ngắn gọn nhưng vi phạm nguyên tắc mà người xây dựng phải chỉ xây dựng đối tượng. Đó có thể không phải là một vấn đề.
  • Cách sao chép ngắn gọn mặc dù bạn cần phải gọi điện cho mỗi lớp.
  • Cách gán là Delphi hơn. Nó tách riêng quá trình tạo và khởi tạo, điều này là tốt bởi vì chúng ta thích khái niệm một phương thức của một phương thức làm cho mã tốt hơn để duy trì.

Và nếu bạn triển khai Gán sử dụng luồng, bạn chỉ có một nơi để lo lắng về trường nào cần có sẵn.

3

Tôi thích kiểu bản sao - nhưng chỉ bằng Java (hoặc bất kỳ ngôn ngữ GC nào khác). Tôi sử dụng nó một số lần ở Delphi, nhưng chủ yếu là tôi ở lại với CreateAssign, bởi vì nó là rõ ràng hơn nhiều người chịu trách nhiệm cho sự phá hủy của đối tượng.

+2

Tôi thường ghét sử dụng các nhà thầu với các đối số. Khi bạn bắt đầu làm cho khuôn khổ của bạn phức tạp hơn, nó bắt đầu cắn bạn trong

+1

Tôi thực sự thích các nhà thầu thực thi vượt qua tất cả các đối tượng cần thiết, như 'Tạo (AOwner)'.Khung tiêm phụ thuộc biết cả hai hương vị, tiêm phụ thuộc dựa trên thuộc tính hoặc Constructor - cả hai đều có ưu điểm (và khuyết điểm) của chúng. – mjn

+0

@mjustin: tôi cũng vậy, nhưng tôi thường không sử dụng các nhà thầu để tạo một bản sao. – splash

Các vấn đề liên quan