2010-09-14 38 views

Trả lời

32

Vâng, không nhiều lắm. Nó nhận được một đề cập đặc biệt trong Framework Design Guidelines như một giao diện để tránh.

Không thực hiện ICloneable. Có là hai cách chung để triển khai Có thể thao tác được, dưới dạng sâu hoặc bản sao không sâu. Sao chép sâu các đối tượng được nhân bản và tất cả các đối tượng được tham chiếu bởi đối tượng, đệ quy cho đến khi tất cả các đối tượng trong biểu đồ được sao chép . Bản sao không sâu (được gọi là dưới dạng ‘nông’ nếu chỉ các tài liệu tham khảo cấp cao nhất mới được sao chép) có thể không có hoặc một phần của bản sao sâu. Bởi vì hợp đồng giao diện không chỉ định loại bản sao được thực hiện, các lớp khác nhau có các triển khai khác nhau. Người tiêu dùng không thể dựa vào ICloneable để cho họ biết liệu một đối tượng có được nhân bản sâu hay không không.

Đã có cuộc thảo luận trong quá khứ về việc lỗi thời. Tôi không chắc chắn những gì đã từng đến từ đó, nhưng các nhà thiết kế khung đã thừa nhận rằng nó có lẽ là một sai lầm.

Nếu bạn muốn hỗ trợ nhân bản thì tôi sẽ tạo và triển khai các giao diện riêng biệt IDeepCopyIShallowCopy hoặc tương tự.

+3

+1, trả lời đúng. –

4

Tạo bản sao của đối tượng được chỉ định.

ICloneable Interface:

Hỗ trợ nhân bản, mà tạo ra một dụ mới của một lớp với cùng một giá trị như một thể hiện.

EDIT: Scott Chamberlain hoàn toàn đúng. Giao diện này không chỉ định hoặc bản sao này phải sâu hoặc nông. Và đây là một trong những điều khó hiểu nhất về giao diện này.

+0

Chỉ trong trường hợp bạn không biết những gì một bản sao sâu là http://en.wikipedia.org/wiki/Object_copy#Deep_copy –

+0

"Clone có thể được thực hiện hoặc là một bản sao sâu hoặc một bản sao cạn. Trong một bản sao sâu, tất cả các đối tượng được sao chép, trong khi, trong một bản sao nông, chỉ có các đối tượng cấp cao nhất được nhân đôi và các cấp thấp hơn chứa các tham chiếu. " - Tài liệu MSDN cho ICloneable.Clone. Vì vậy, đừng cho rằng đó là một bản sao sâu. – Powerlord

+0

@R. Bemrose: vâng, đúng rồi. Tôi đã chỉnh sửa câu trả lời của mình. –

5

Từ MSDN: "Giao diện ICloneable chứa một thành viên, Clone, được thiết kế để hỗ trợ nhân bản ngoài cung cấp bởi MemberwiseClone."

Đó là một giao diện nếu thực hiện các dấu hiệu cho thấy các cá thể của lớp được nhân bản và không chỉ được sao chép cạn. Thực hiện giao diện IClonable không nói bất cứ điều gì về nếu nó nông sao chép hoặc sao chép sâu, mặc dù.

Có một cuộc thảo luận thú vị về cách sử dụng IClonable tại đây: http://channel9.msdn.com/forums/TechOff/202972-IClonable-deep-vs-shallow-best-practise/.

1

Tôi nghĩ rằng tôi đã tìm ra cách sử dụng tốt cho iCloneable: để tạo thuận lợi cho việc tạo ra các hệ thống phân cấp lớp bao gồm cả các loại cloneable và không cloneable.

Nếu một lớp có phương thức sao chép công khai, thì không thể lấy được từ một lớp không thể được nhân bản vô nghĩa, mà không vi phạm Nguyên tắc thay thế Liskov. Vấn đề là đối với bất kỳ lớp học nào, có thể hữu ích khi có cả một phiên bản có khả năng cloneable, và một phiên bản cho phép các lớp dẫn xuất không có khả năng cloneable.iCloneable cung cấp một cách để làm điều này.

Giả sử bạn muốn xác định thứ bậc lớp Widget, SuperWidget và SuperDuperWidget và SuperDuperNoncloneableWidget. Widget, SuperWidget và SuperDuperWidget có thể hỗ trợ nhân bản thông qua phương thức được bảo vệ. Người ta có thể lấy được từ họ các lớp CloneableWidget, CloneableSuperWidget, và CloneableSuperDuperWidget.

Nếu không sử dụng iCloneable (hoặc một cái gì đó tương đương), sẽ rất khó để viết một hàm hoạt động trên CloneableWidget, nhưng cũng có thể hoạt động trên CloneableSuperWidget. Sử dụng iCloneable, tuy nhiên, người ta có thể có chức năng của một người chấp nhận một Widget, và cũng yêu cầu rằng nó được iCloneable. Do đó, điều này sẽ cho phép một hoạt động độc đáo trong hệ thống phân cấp mong muốn.

Lưu ý rằng không giống như một số giao diện khác, iCloneable không có ý nghĩa trong sự cô lập. Nó chỉ hữu ích như một ràng buộc kiểu khi được áp dụng cho một lớp mà có thể hoặc có thể không hỗ trợ công khai nhân bản; các ngữ nghĩa nông/sâu sẽ là những ngữ nghĩa của lớp đó.

0

Điều gì về việc xác định IShallowClone và IDeepClone như thế này?

public interface IShallowClone<T> { T ShallowClone(); } 
public interface IDeepClone<T> { T DeepClone(); } 

public interface IA : IShallowClone<IA>, IDeepClone<IA> { double a { get; } IA ia { get; } } 
public interface IB : IA, IShallowClone<IB>, IDeepClone<IB> { double b { get; } IB ib { get; } } 

public class A : IA 
{ 
    public double a { get; private set; } 
    public IA ia { get; private set; } 
    public A(IA that) { this.a = that.a; this.ia = (ia as IDeepClone<IA>).DeepClone(); } 
    public IA DeepClone() { return new A(this); } 
    public IA ShallowClone() { return this.MemberwiseClone() as IA; } 
} 
public class B : A, IB 
{ public double b { get; private set; } 
    public IB ib { get; private set; } 
    public B(IB that) : base(that) { this.b = that.b; this.ib = (ib as IDeepClone<IB>).DeepClone(); } 
    public new IB DeepClone() { return new B(this); } 
    public new IB ShallowClone() { return this.MemberwiseClone() as IB; } 
} 
Các vấn đề liên quan