2009-03-19 15 views
7

मैं एक पुराने जावा कोड बेस (जेवीएम 1.4) का रखरखाव कर रहा हूं जो ऑब्जेक्ट इंस्टेंटेशन के विकल्प के रूप में क्लोनिंग का उपयोग करने लगता है, मैं प्रदर्शन अनुकूलन के रूप में अनुमान लगा रहा हूं। यहाँ एक काल्पनिक उदाहरण है:क्लोनिंग कन्स्ट्रक्टर/कारखाने के तरीकों पर प्रदर्शन सुधार प्रदान करता है?

public class Foo { 
    private SomeObject obj; // SomeObject implements Cloneable 
    public Foo() { 
    obj = new SomeObject(); 
    obj.setField1("abc"); // these fields will have the same value every time 
    obj.setField2("def"); 
    } 
    public void doStuff() { 
    SomeObject newObj = obj.clone(); // clone it instead of using a factory method 
    // do stuff with newObj 
    } 
} 

समय से पहले अनुकूलन, के होते हुए भी यह वास्तव में कुछ बिंदु पर एक सिफारिश मुहावरा था के बारे में सामान्य चेतावनियां?

+0

यह अजीब लगता है। मैं नए ऑब्जेक्ट इंस्टेंटेशन के लिए कन्स्ट्रक्टर का उपयोग करूंगा। –

उत्तर

3

कॉपी कन्स्ट्रक्टर या फैक्ट्री विधि के बजाय clone() का आह्वान करने का एक कारण यह है कि अन्य विकल्पों में से कोई भी विकल्प उपलब्ध नहीं हो सकता है।

एक उथले ऑब्जेक्ट कॉपी (गहरी प्रतिलिपि अधिक शामिल है) करने के लिए clone() लागू करने के लिए एक प्रतिलिपि बनाने के लिए एक कॉपी कन्स्ट्रक्टर या फैक्ट्री विधि को लागू करने की तुलना में तुच्छ है। clone() को लागू करने के लिए, किसी वर्ग को केवल Cloneable इंटरफ़ेस को कार्यान्वित करने की आवश्यकता है और को ओवरराइड करें जो super.clone() को आमंत्रित करता है जो आम तौर पर Object.clone() को आमंत्रित करता है। Object.clone() मूल ऑब्जेक्ट की प्रत्येक प्रॉपर्टी को डुप्लिकेट की इसी प्रॉपर्टी में कॉपी करता है, इस प्रकार एक उथली प्रतिलिपि बनाता है।

हालांकि clone() लागू करना सरल है, फिर भी Cloneable को लागू करना भूलना आसान है। नतीजतन, किसी ऑब्जेक्ट को डुप्लिकेट करने के लिए clone() का उपयोग करने का संभावित जोखिम यह है कि यदि उस ऑब्जेक्ट का वर्ग Cloneable और clone() लागू करने के लिए उपेक्षा करता है तो Object.clone() या तो सीधे या अप्रत्यक्ष रूप से आमंत्रित करता है, यह CloneNotSupportedException फेंक देगा।

इस code example और पिछले discussionCloneable इंटरफ़ेस का poor design पर देखें।

4

संभवतः वे एक प्रतिलिपि चाहते थे। शायद वे इसे किसी अन्य समारोह में पास करना चाहते हैं, और यह सुनिश्चित नहीं हो सकता कि वह फ़ंक्शन इसे नहीं बदलेगा। यह सुनिश्चित करने का एक तरीका है कि विधि doStuff() उस फू ऑब्जेक्ट की स्थिति के संबंध में है जिसे इसे बुलाया जाता है।

+0

इसे ऊपर उठाकर +1 'कारण (कोड को देखने के बाद) यह मेरे अधिक गूढ़ उत्तर से लागू होने की संभावना है या अधिक होने की संभावना है। – MarkusQ

+0

ध्यान दें कि यह क्लोनिंग का प्राथमिक उद्देश्य है (मान लीजिए कि मेरे प्रोफेसरों को पता था कि वे किस बारे में बात कर रहे थे)। – Chris

+0

+1: हाँ, ऐसा लगता है कि '.clone() 'पास-दर-मूल्य का जावाश तरीका है। –

1

यह प्रदर्शन प्रदर्शन अनुकूलन हो सकता है, इस पर निर्भर करता है कि रचनाकारों में कितना काम किया जाता है।

यह अधिक संभावना है क्योंकि अर्थशास्त्र अलग हैं। क्लोनिंग एक ऐसी भाषा में "प्रोटोटाइप अर्थशास्त्र" (जैसे जावास्क्रिप्ट, स्वयं, इत्यादि) को लागू करने का एक तरीका प्रदान करता है जो आम तौर पर उस तरह से नहीं होता है।

+0

कैसा है? हालांकि प्रोटोटाइप अर्थशास्त्र का मतलब है कि आप कन्स्ट्रक्टर या अन्य फ़ील्ड या रनटाइम पर विधियों के व्यवहार को बदल सकते हैं। –

+0

क्लोनिंग आपको आरंभिक मान आदि सेट करने देता है और (प्रतिनिधियों का उपयोग करके) व्यवहार को भी बदल देता है। यह एक प्रकार का कड़वाहट है, लेकिन आप आम तौर पर रस से थोड़ा सा स्व-स्टाइल सेमेटिक्स नहीं उड़ाते हैं, इसलिए यह अक्सर अभ्यास में काम करता है। – MarkusQ

0

यदि कुछ ऑब्जेक्ट कन्स्ट्रक्टर महंगा काम करता है, जैसे किसी डेटाबेस से कुछ पकड़ना या किसी चीज़ को पार्स करना, या क्लोन को काम करने से बचने के लिए समझदारी होगी।

यदि निर्माता कुछ भी नहीं करता है तो वास्तव में क्लोन का उपयोग करने की आवश्यकता नहीं है।

संपादित करें: कहा कि क्लोन को दिखाने के लिए कोड निर्माता के रूप में ही काम करने के लिए नहीं है:

class Main 
    implements Cloneable 
{ 
    private final double pi; 

    public Main() 
    { 
     System.out.println("in Main"); 
     // compute pi to 1,000,000,000 decimal palaces 
     pi = 3.14f; 
    } 

    public Object clone() 
    { 
     try 
     { 
      return (super.clone()); 
     } 
     catch(final CloneNotSupportedException ex) 
     { 
      throw new Error(); // would not throw this in real code 
     } 
    } 


    public String toString() 
    { 
     return (Double.toString(pi)); 
    } 

    public static void main(String[] args) 
    { 
     final Main a; 
     final Main b; 

     a = new Main(); 
     b = (Main)a.clone(); 

     System.out.println("a = " + a); 
     System.out.println("b = " + b); 
    } 
} 

मुख्य कंसट्रक्टर कहा जाता है एक बार, कंप्यूटिंग अनुकरणीय एक बार किया जाता है।

+0

यदि आप कम से कम कुछ चिह्नित करने जा रहे हैं तो कम से कम उस पर टिप्पणी करें जो आपको लगता है कि इसके बारे में गलत है! – TofuBeer

+0

यदि कॉपी कन्स्ट्रक्टर ने महंगा काम किया है, तो क्लोन को भी ऐसा करना होगा। –

+0

क्लोन कन्स्ट्रक्टर को बाईपास करता है - आपको यह कैसे करना होगा? – TofuBeer

2

कॉपी कन्स्ट्रक्टर के साथ एक बड़ी समस्या यह है कि ऑब्जेक्ट का प्रकार संकलन समय पर जाना जाना चाहिए।यदि एक विरासत वर्ग एक कॉपी कन्स्ट्रक्टर का समर्थन करता है, और कन्स्ट्रक्टर को व्युत्पन्न-वर्ग ऑब्जेक्ट पास किया जाता है, तो कन्स्ट्रक्टर बेस-क्लास ऑब्जेक्ट का उत्पादन करेगा जिसका बेस-क्लास गुण आमतौर पर पारित ऑब्जेक्ट से मेल खाता है, लेकिन नई ऑब्जेक्ट ' किसी भी फीचर का समर्थन नहीं करता जो पास-इन ऑब्जेक्ट में मौजूद था जो बेस क्लास में मौजूद नहीं था।

एक प्रतिलिपि बनाने वाले "संरक्षित" बनाकर कुछ हद तक इस समस्या को हल करना संभव है, और प्रत्येक व्युत्पन्न कक्षा में एक अतिरंजित फैक्ट्री कॉपी विधि है जो उस वर्ग की अपनी प्रतिलिपि निर्माता कहती है, जो बदले में इसके आधार की प्रतिलिपि बनाता है कक्षा। प्रत्येक व्युत्पन्न वर्ग को एक कॉपी कन्स्ट्रक्टर और प्रतिलिपि विधि के ओवरराइड की आवश्यकता होगी, हालांकि, यह कोई नया फ़ील्ड जोड़ता है या नहीं। यदि केस क्लास "क्लोन" का उपयोग करती है, तो यह अतिरिक्त कोड समाप्त किया जा सकता है।