2010-12-01 12 views
6

मुझे जावा में एक उप-वर्ग क्लोन करने की आवश्यकता है, लेकिन उस बिंदु पर जहां कोड होता है, मुझे सबक्लास प्रकार, केवल सुपर क्लास नहीं पता होगा। ऐसा करने के लिए सबसे अच्छा डिजाइन पैटर्न क्या है?जावा में क्लोनिंग उप-वर्ग

उदाहरण:

class Foo { 
    ... 
    public Foo copy() { 
     return new Foo(this); 
    } 
} 
class Bar extends Foo { 
    ... 
    @Override public Bar copy() { 
     return new Bar(this); 
    } 
} 

(आदर्श रूप में कक्षाएं या तो सार या प्रभावी ढंग से करते हैं:

class Foo { 
    String myFoo; 
    public Foo(){} 
    public Foo(Foo old) { 
     this.myFoo = old.myFoo; 
    } 
} 

class Bar extends Foo { 
    String myBar; 
    public Bar(){} 
    public Bar(Bar old) { 
     super(old); // copies myFoo 
     this.myBar = old.myBar; 
    } 
} 

class Copier { 
    Foo foo; 

    public Foo makeCopy(Foo oldFoo) { 

     // this doesn't work if oldFoo is actually an 
     // instance of Bar, because myBar is not copied 
     Foo newFoo = new Foo(oldFoo); 
     return newFoo; 

     // unfortunately, I can't predict what oldFoo's the actual class 
     // is, so I can't go: 
     // if (oldFoo instanceof Bar) { // copy Bar here } 
    } 
} 

उत्तर

6

आप कक्षाएं आप प्रतिलिपि बनाना चाहते हैं, उसका नियंत्रण है, तो एक आभासी विधि आगे रास्ता है अंतिम।)

+0

नहीं, काम नहीं करता है। इसे आज़माएं: बार बार = नया बार(); फू foo = बार; foo.copy()। यह Foo.copy(), बार नहीं होगा।कॉपी() – ccleve

+2

@ user237815 मुझे ऐसा नहीं लगता है। 'Bar.copy' ओवरराइड (' @ ओवरराइड' के साथ चेक किया गया) 'Foo.copy'। –

+0

टॉम सही है। 'प्रतिलिपि' का आवेषण रनटाइम पर होता है और JVM ऑब्जेक्ट के प्रकार के आधार पर उपयुक्त 'प्रतिलिपि' विधि को कॉल करेगा। –

0

ऐसा करने का तरीका Foo और Bar में एक विधि newInstance() बनाना है। दोनों कार्यान्वयन सही प्रकार का ऑब्जेक्ट बना सकते हैं और उसे वापस कर सकते हैं, कॉपी करने वाले कोड को केवल यह पता होना चाहिए कि ऑब्जेक्ट की प्रति प्राप्त करने के लिए इसे oldFoo.newInstance() का उपयोग करना होगा।

+0

मेरे लिए नया नाम() नाम एक नई असंबंधित वस्तु का तात्पर्य है, न कि प्रतिलिपि/क्लोन। –

+0

मैंने जवाब जोड़ने के बाद इस तरह की प्रतिक्रिया की उम्मीद की थी ... विधि का नाम उन संदर्भ/अवधारणाओं पर निर्भर करता है जिन्हें आप व्यक्त करना चाहते हैं (जैसे प्रतिलिपि, क्लोन, getInstance, आदि) तो उत्तर में उपयोग की जाने वाली किसी भी विधि का नाम उदाहरण है शायद ओपी क्या उपयोग करने जा रहा है नहीं। मेरे लिए नया नाम नाम एक नया ऑब्जेक्ट उदाहरण सिग्नल करता है जो इस मामले में नई इंस्टेंस विधि को निष्पादित करने वाले ऑब्जेक्ट के मानों के साथ प्रारंभ किया जा सकता है। (एक स्थिर नई स्थापना विधि के विपरीत।) – rsp

0

यदि आपको किसी वस्तु को गहरा क्लोन करने की आवश्यकता है, तो जावा क्रमिकरण का उपयोग करने का सबसे अच्छा तरीका है। इसकी आवश्यकता है कि ऑब्जेक्ट Serializable लागू करता है लेकिन यह मूल रूप से साझा किए गए संदर्भों के साथ एक पूरी तरह से नया, क्लोन ऑब्जेक्ट बनाएगा।

आप अपनी प्राथमिक श्रेणी को सीरियलज़ेबल लागू कर सकते हैं, जिससे प्रत्येक सबक्लास स्वचालित रूप से इसका समर्थन करेगा।

आखिरकार, इसे शायद कम स्मृति का उपयोग करने के लिए बाइटएरे ऑटपुटस्ट्रीम के बजाय पाइप स्ट्रीम का उपयोग करने के लिए अपडेट किया जा सकता है और तेज हो सकता है, लेकिन यदि आपके पास छोटी वस्तुएं हैं तो यह ध्यान देने योग्य नहीं होगा।

public static<T> T clone(T object) { 
    try { 
     ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 
     ObjectOutputStream out = new ObjectOutputStream(bOut); 
     out.writeObject(object); 
     out.close(); 

     ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); 
     T copy = (T)in.readObject(); 
     in.close(); 

     return copy; 
    } 
    catch(Exception e) { 
     throw new RuntimeException(e); 
    } 
} 
0

मुझे यकीन नहीं है कि यह आपकी आवश्यकताओं को ठीक से फिट करता है, लेकिन मैं Factory pattern पर एक नज़र डालने का सुझाव दूंगा।

3

जावा में सबसे मानक तरीका प्रत्येक वर्ग कि Cloneable लागू प्रतिलिपित किया जा सकता है, और है कि उस वर्ग के लिए appropiately क्लोनिंग करता है एक सार्वजनिक संस्करण के साथ Object.clone() ओवरराइड करने के लिए किया जाएगा (डिफ़ॉल्ट रूप से Object.clone() वस्तु की एक उथले प्रतिलिपि बनाता है) ।

ध्यान दें कि कई लोग सोचते हैं कि Cloneable/Object.clone() खराब डिज़ाइन है।

2

यदि आप में क्लोन/क्लोनबल लागू करते हैं तो सही तरीके आपके पास कोई सुपर क्लास समस्या नहीं होगी। ऐसा इसलिए है क्योंकि ऑब्जेक्ट.क्लोन() एक बहुत ही विशेष विधि है - बहुत ही ब्रीफ विवरण में: ऑब्जेक्ट.क्लोन() हमेशा उसी प्रकार के ऑब्जेक्ट को वापस लाएगा जिसे इसे बुलाया जाता है।

@see http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#clone%28%29

तो क्लोन और clonable का सही कार्यान्वयन होगा:

class Foo implements Clonable{ 
    String myFoo; 
    ... 
    Foo clone() { 
     try { 
     Foo clone = (Foo) super.clone(); 
     clone.myFoo = this.myFoo; 
     return clone; 
     } catch (CloneNotSupportedException e) { 
     throw new RuntimeException("this could never happen", e); 
     } 
    } 
} 

class Bar extends Foo { 
    String myBar; 
    ... 
    Bar clone() { 
     try { 
     Bar clone = (Bar) super.clone(); 
     clone.myBar = this.myBar(); 
     return clone; 
     } catch (CloneNotSupportedException e) { 
     throw new RuntimeException("this could never happen", e); 
     } 
    } 
} 

फिर कॉपियर की प्रक्रिया आसान है:

class Copier { 
    Foo foo; 

    /** 
    * @return return a Foo if oldFoo is of class Foo, return Bar if oldClass is of class Bar. 
    */ 
    public Foo makeCopy(Foo oldFoo) { 
    return oldFoo.clone(); 
    } 
} 
0

यह पैटर्न/समाधान एक का उपयोग करता है कॉपी कन्स्ट्रक्टरों का संयोजन और ओवरराइड टाइप किए गए आभासी कार्यों, और प्रत्येक सुपरक्लास के लिए उदाहरण प्रसारित करता है।

public class A { 
    private String myA; 

    public A(A a) { 
     myA = a.myA; 
    } 

    public A copy() { 
     return new A(this); 
    } 
} 

public class B extends A { 
    private String myB; 

    public B(B b) { 
     super(b); 
     myB = b.myB; 
    } 

    public B copy() { 
     return new B(this); 
    } 
} 

public class C extends B { 
    private String myC; 

    public C(C c) { 
     super(c); 
     this.myC = c.myC; 
    } 

    public C copy() { 
     return new C(this); 
    } 
} 
संबंधित मुद्दे