2009-04-26 16 views
6

Trong dự án Java của tôi, tôi có một vectơ các loại Thương nhân khác nhau. Các loại giao dịch khác nhau này là các lớp con của lớp Trader. Ngay bây giờ, tôi có một phương thức lấy Trader làm đối số và lưu trữ nó 50 lần hoặc hơn trong vectơ. Tôi đang gặp vấn đề bởi vì lưu trữ cùng một đối tượng 50 lần chỉ lưu trữ 50 tài liệu tham khảo của cùng một đối tượng. Tôi cần lưu trữ 50 bản sao của đối tượng. Tôi đã nghiên cứu về việc triển khai thực hiện Clone, nhưng tôi không muốn các lập trình viên xác định một loại Trader phải lo lắng về việc tạo lớp học của họ cloneable. Ngoài ra, như được chỉ ra bởi this page, việc thực hiện sao chép tạo ra tất cả các loại vấn đề. Tôi không nghĩ rằng một nhà xây dựng bản sao sẽ làm việc hoặc vì nếu tôi đã xác định một trong lớp Trader, nó sẽ không biết loại Trader mà nó đã sao chép và chỉ tạo một Trader chung. Tôi có thể làm gì?Có cách nào khác để thực hiện Clone trong Java không?

Chỉnh sửa: Tôi không thực sự muốn tạo bản sao chính xác của một đối tượng nhất định. Những gì tôi thực sự cố gắng làm là để thêm một số lượng nhất định của thương nhân để vector. Vấn đề là người dùng cần phải xác định trong một đối số mà loại Trader mà anh ta muốn thêm vào. Đây là một ví dụ về những gì tôi đang cố gắng làm: (mặc dù cú pháp của tôi hoàn toàn là tưởng tượng)

public void addTraders(*traderType*) 
{ 
    tradervect.add(new *traderType*()) 
} 

Làm thế nào tôi có thể đạt được một cái gì đó như thế này trong Java?

Trả lời

2

Chỉ cần thêm một phương pháp sao chép trừu tượng. Bạn có thể sử dụng các kiểu trả về biến đổi để kiểu dẫn xuất được xác định để trả về một cá thể có nguồn gốc, có thể hoặc có thể không quan trọng.

public interface Trader { 
    Trader copyTrader(); 
    ... 
} 


public final class MyTrader implements Trader { 
    MyTrader copyTrader() { 
     return new MyTrader(this); 
    } 
    ... 
} 

Đôi khi bạn có thể muốn quát đối phó với một bộ sưu tập các loại có nguồn gốc của Trader mà cần phải sao chép và sau đó trả lại một bộ sưu tập đánh máy đúng cách. Cho rằng bạn có thể sử dụng Generics một cách thành ngữ:

public interface Trader<THIS extends Trader> { 
    THIS copyTrader(); 
    ... 
} 


public final class MyTrader implements Trader<MyTrader> { 
    public MyTrader copyTrader() { 
     return new MyTrader(this); 
    } 
    ... 
} 
+0

Tôi không thấy làm thế nào tôi có thể làm cho lớp Trader chung một giao diện vì lớp Trader có các phương thức cần truy cập. Tạo một giao diện có nghĩa là tất cả các phương thức mức thấp đó sẽ không cho phép các phương thức đó được định nghĩa trong lớp Trader. –

+0

Cho dù Trader là một lớp trừu tượng hoặc giao diện là không liên quan. Nói chung một giao diện được ưa thích hơn một lớp trừu tượng. Cũng thích phái đoàn thừa kế. –

0

Một tùy chọn: Nếu bạn có thể làm cho các đối tượng có thể tuần tự hóa, bạn có thể tuần tự hóa sau đó deserialize nó để tạo một bản sao, tương tự như những gì xảy ra khi truyền một đối tượng qua RMI.

phương pháp sao chép nhanh:

public MyObject copy() { 
    ObjectOutputStream oos = null; 
    ObjectInputStream ois = null; 
    try { 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     oos = new ObjectOutputStream(bos); 
     oos.writeObject(this); 
     oos.flush(); 
     ByteArrayInputStream bin = 
      new ByteArrayInputStream(bos.toByteArray()); 
     ois = new ObjectInputStream(bin); 
     return (MyObject)ois.readObject(); 
    } catch(Exception e) { 
     return null; 
    } finally { 
     try { 
      oos.close(); 
      ois.close(); 
     } catch (Exception e) { 
      return null; 
     } 
    } 
} 
+0

Tại sao bạn nên downvote? Đó là một cách thích hợp để comying một đối tượng phức tạp. Việc quản lý tài nguyên là hoàn toàn và hoàn toàn bị phá vỡ mặc dù. –

+0

Đó có phải là giải pháp duy nhất không? Tôi dường như không thể khiến bản thân tin rằng một chiến dịch đơn giản như vậy sẽ gây ra rất nhiều phiền toái. Điều gì sẽ xảy ra nếu tôi thực hiện Clone để cho phép sao chép. Liệu điều đó có thể xảy ra được không? –

+0

@Tom: Không chắc chắn, nhưng sử dụng serializing/deserializing cho nhân bản là về tinh tế như sử dụng memcpy thay vì các nhà xây dựng bản sao trong C + +. – Uri

-2

Một cách là làm cho nó một lớp học chính thức như String riêng Java, mà sẽ thực hiện bất kỳ thay đổi đến một đối tượng của lớp Trader để tạo ra một bản sao mới trong bộ nhớ , nhưng nó sẽ làm cho nó không thể phân lớp nó.

Cách khác (tốt hơn) là sử dụng phương pháp nhà máy để tạo và sao chép Trader objexts, ngụ ý rằng bạn không được cho phép hàm tạo mặc định được sử dụng tức là làm cho riêng tư. Bằng cách này bạn có thể kiểm soát số lượng các cá thể mà lớp đó có. Xem http://en.wikipedia.org/wiki/Factory_method

public class Trader { 

    /* prevent constructor so new cant be used outside the factory method */ 
    private Trader() { 
    } 

    /* the factory method */ 
    public static Trader createTrader(int whatKindOfTrader) { 

     switch (whatKindOfTrader) { 
     case 0: 
      return new Trader1(); // extends Trader 
     case 1: 
     default: 
      return new Trader2(); // extends Trader 
     } 
     return new Trader3(); // or throw exception 
    } 
} 

Bạn thậm chí có thể chỉ định một phương pháp quá tải, hoặc một cuộc tranh luận thứ hai mà phải mất một Trader và sao chép nó vào một hình mới, do đó thay thế clone. Btw, bạn có thể muốn ghi đè lên phương thức clone() và ném CloneNotSupportedException, để ngăn chặn đối tượng Nhân bản mặc định.

+0

Bạn có nghĩa là bất biến hơn là chỉ là một lớp học cuối cùng. Tính bất biến có lẽ sẽ hơi xa một đối tượng "thương nhân". –

+0

Tôi không thay đổi, nhưng cuối cùng. Có một sự khác biệt, và cá nhân tôi sẽ không bao giờ sử dụng nó. Nhưng, phương pháp Nhà máy là phương pháp tốt nhất, và nó là mẫu thiết kế chung Btw, đối tượng không thay đổi chỉ là không hữu ích trong trường hợp này. – Azder

2

Tôi không rõ lý do tại sao bạn muốn lưu trữ 50 hoặc nhiều bản sao của cùng một đối tượng trừ khi họ giao dịch gốc làm mẫu thử nghiệm (xem mẫu) cho các nhà giao dịch sau này.

Nếu bạn muốn tạo bản sao chính xác của đối tượng, bạn phải tính đến vấn đề đa hình. Nếu mọi người subclassing class đã cho của bạn được phép thêm các thành viên state, thì bạn đã có đủ đau đầu với các hàm như equals và compareTo, clone đó sẽ thêm một trường hợp nữa mà bạn cần phải xử lý đặc biệt.

Tôi không đồng ý rằng bản sao luôn luôn là điều xấu, đôi khi cần thiết. Tuy nhiên, trong các tình huống phân lớp, rất nhiều thứ trở nên phức tạp.

Tôi khuyên bạn nên đọc (khi bạn có cơ hội) "Java hiệu quả" của Bloch, bao gồm rất nhiều chủ đề của anh ấy. Quan điểm của Bracha là không nên để người khác mở rộng các lớp học của bạn, và nếu bạn làm thế, bạn cần ghi chép rất rõ những gì họ sẽ phải làm và hy vọng họ làm theo hướng dẫn của bạn. Có thực sự không phải là một cách để bỏ qua điều đó. Bạn cũng có thể muốn làm cho Nhà giao dịch của bạn bất biến.

Tiến hành thực hiện Clone bình thường và chỉ ra rất rõ ràng trong tiêu đề lớp mà bất kỳ ai thừa hưởng từ Trader của bạn và thêm thành viên tiểu bang phải triển khai phương thức X (chỉ định).

Tìm các thủ thuật để bỏ qua một Cloneable thực tế và vẫn sao chép sẽ không khắc phục được vấn đề thừa kế. Không có viên đạn bạc ở đây.

+0

Câu trả lời của bạn khiến tôi suy nghĩ. Xem chỉnh sửa tôi đã thực hiện để biết thêm thông tin.:) –

+0

Chờ đợi, về cơ bản bạn có nói rằng nếu X mở rộng Trader, và ai đó đã chuyển một thể hiện X vào hàm của bạn, bạn muốn nhận một X mới khác không? – Uri

+0

Nếu bạn muốn hành vi này, bạn sử dụng thành ngữ getClass.newInstance (khủng khiếp): traderType.getClass(). NewInstance() Bạn phải đảm bảo luôn có hàm khởi tạo công khai và bạn có thể muốn một số init phương pháp bạn luôn có thể gọi để đưa nó vào trạng thái hợp pháp. – Uri

0

Quyền của Uri, đa hình với trạng thái mở ra một lượng lớn giun.

Tôi nghĩ rằng việc phân lớp Cloneable và ghi đè lên bản sao() có lẽ là cách đơn giản nhất để thực hiện. Bạn có thể, tôi tin rằng, làm cho biến thể loại trả về.

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