2013-06-12 13 views
8

Làm thế nào bạn viết một hàm tạo bản sao cho một lớp có các biến thành viên giao diện?Có thể viết các hàm tạo bản sao cho các lớp với các biến thành viên giao diện trong Java không?

Ví dụ:

public class House{ 

    // IAnimal is an interface 
    IAnimal pet; 

    public House(IAnimal pet){ 
     this.pet = pet; 
    } 

    // my (non-working) attempt at a copy constructor 
    public House(House houseIn){ 
     // The following line doesn't work because IAnimal (an interface) doesn't 
     // have a copy constructor 
     this.pet = new IAnimal(houseIn.pet); 
    } 
} 

Am Tôi buộc phải có một bê tông Animal? Nếu có, có vẻ như việc sử dụng lại lớp học cho những ngôi nhà có chó và nhà với mèo trở nên phức tạp!

+1

Nếu bạn muốn có một bản sao sâu, bạn nên triển khai một trình tạo bản sao trong Động vật. – alfasin

+1

Bạn không thể chỉ đơn giản là thực hiện một bản sao-constructor trong động vật. Trong trường hợp này bạn có IAnimal, một giao diện. Vì vậy, bạn sẽ cần biết lớp bê tông nào bạn cần để khởi tạo. – Mene

Trả lời

6

Bạn có một trong ba lựa chọn:

  1. Có một phương pháp trên IAnimal nhân bản sâu sắc đối tượng (được sử dụng bởi các thư viện như giao diện DOM như Node.cloneNode(boolean))
  2. Tạo một trình tạo bản sao trong tất cả các lần triển khai IAnimal có loại bê tông và làm cho yêu cầu nt trong hợp đồng giao diện, sau đó sử dụng phản ánh để truy cập nó
  3. Tạo một nhà máy copy sẽ copy từng thực hiện bằng tay
  4. Sử dụng thư viện của bên thứ 3 mà thực hiện nhân bản sâu sắc đối với bạn với các hợp đồng riêng của mình, chẳng hạn như không-args các nhà xây dựng, các trường phi chính thức, Serializable lớp học, v.v., Giống như những người được liệt kê here

Sao chép Phương pháp

Đối # 1, làm như sau:

public interface IAnimal { 
    IAnimal cloneDeep(); 
} 

Thực hiện rằng trong các loại bê tông, sau đó gọi phương thức đó để sao chép nó:

this.pet = pet.cloneDeep(); 

Sau đó ghi lại yêu cầu trong giao diện, nói rằng omething dọc theo dòng:

Triển khai các giao diện này phải trả về một đối tượng mà không == là trường hợp này, và phải được nhân bản sâu sắc để thao tác của đối tượng này không dẫn đến thao tác của trả lại một và ngược lại.

Triển khai sẽ phải tuân theo hợp đồng này để tuân thủ giao diện, nhưng điều này sẽ không được thực thi tại thời điểm biên dịch.

Sao chép Constructor

Cố gắng truy cập vào một constructor sao chép phản tư, sau đó nói rằng một constructor sao chép là cần thiết trong tất cả triển khai cụ thể trong giao diện, mà trở thành một phần của hợp đồng giao diện. Mỗi thực hiện sau đó sẽ trông như thế này:

public class Dog implements IAnimal { 

    private String name; 

    public Dog(Dog dog) { 
     this.name = dog.name; 
    } 
} 

Và sau đó tất cả bạn cần là một phương pháp duy nhất để sao chép tất cả các thực hiện:

public static <A extends IAnimal> A copy(A animal) { 
    Class<?> animalType = animal.getClass(); 
    // This next line throws a number of checked exceptions you need to catch 
    return (A) animalType.getConstructor(animalType).newInstance(animal); 
} 

Một bạn có điều này, thêm một tuyên bố để hiệu ứng này trong của giao diện của bạn tài liệu:

Triển khai giao diện này xác định hàm tạo bản sao tham gia cùng một loại hoặc siêu kiểu của lớp học. Nhà xây dựng này phải tạo một bản sao sâu của đối số để thao tác của đối tượng này không dẫn đến thao tác của đối tượng được trả về và ngược lại.

Một lần nữa, đây là thời gian chạy được thi hành. Phương thức copy ở trên ném các lỗi NoSuchMethodException khi hàm tạo không tồn tại.

Sao chép Factory

này có các IAnimal và sử dụng instanceof để quyết định phương pháp để vượt qua nó để, như:

public static IAnimal copyAnimal(IAnimal animal) { 
    if (animal instanceof Dog) 
     return copyDog((Dog) animal); 
    if (animal instanceof Cat) 
     return copyCat((Cat) animal); 
    //... 
    else 
     throw new IllegalArgumentException("Could not copy animal of type: " 
       + animal.getClass().getName()); 
} 

Sau đó làm việc sao chép sâu trong copy phương pháp đối với từng loại bằng tay .

0

Kiến thức của tôi không có tương đương trực tiếp với điều này trong Java.

Cách "thích hợp" là làm cho Giao diện tự thực hiện Cloanable.

Và cách dễ nhất có thể là sử dụng sự phản chiếu. Tôi biết có một thư viện xử lý các bản sao sâu của các đối tượng tùy ý, nhưng tôi không thể nhớ lại tên đó vào lúc này.

liên quan: Java: recommended solution for deep cloning/copying an instance

+2

'Cloneable' bị hỏng theo nhiều cách, và trong' Hiệu quả Java' Josh Bloch khuyến cáo không sử dụng nó. Nếu bạn không có cuốn sách đó, bạn nên. Xem: http://www.artima.com/intv/bloch13.html –

2

Nếu tôi hiểu vấn đề của bạn, Vì bạn không thể chỉ định nhà xây dựng trong một giao diện bạn sẽ cần phải khai báo một phương pháp sâu bản sao trong giao diện của bạn và thực hiện nó trong lớp học của bạn. Bạn không thể khởi tạo một giao diện. Bạn cũng có thể muốn sao chép sâu bất cứ thứ gì trong House, tùy thuộc vào nhu cầu của bạn.

public interface IAnimal { 
    ... 
    IAnimal deepCopy(); 
} 


public House(House houseIn){ 
    this.pet = houseIn.pet.deepCopy(); 
} 

Vấn đề là bạn có thể không làm điều gì đó sai trái. Nó có mùi giống như bạn không thực sự muốn có một giao diện ở đây, mà là một lớp trừu tượng.

1

ok, hãy để tôi giải thích sự cố trong mã này. lưu ý rằng khi bạn có một giao diện, bạn đang xác định một hành vi không phải là một trừu tượng hoặc nhận dạng của một đối tượng (hoặc sinh vật) chẳng hạn như một Động vật. trong trường hợp này, bạn cần một lớp trừu tượng thay vì một giao diện. bắt đầu nói. bạn không thể có một hàm tạo trên một giao diện (xem Why are we not allowed to specify a constructor in an interface?) do đó sử dụng một giao diện theo cách đó sẽ thất bại.

vân vân trường hợp này tôi sẽ đề nghị sử dụng một lớp trừu tượng thay vì:

public class House { 

AbstractAnimal pet; 

public House(AbstractAnimal pet) { 
    this.pet = pet; 
} 

public House(House houseIn) { 
    this.pet = new AbstractAnimal(houseIn.pet) { 
     //implement the abstract methods that are required for anonymous class 
    }; 
} 

private abstract class AbstractAnimal { 
    //Abstract class attributes 

    public AbstractAnimal(AbstractAnimal Parent) { 
     //Constructor code, can also call abstract methods if required 
    } 
    //declare Abstract methods if required. 
} 
Các vấn đề liên quan