2015-12-15 4 views
11

मैं एक जावा क्लास बनाने की कोशिश कर रहा हूं जो एकाधिक Closeable संसाधनों का प्रबंधन करता है। सी ++ समाधान सरल और संसाधनों की एक बड़ी संख्या के साथ आसानी से स्केलेबल होगा:जावा में बंद करने योग्य वस्तुओं को कैसे लिखें?

class composed_resource 
{ 
    resource_a a; 
    resource_b b; 
    resource_c c; 

    composed_resource(int x) 
     : a(x), b(x), c(x) 
    { } 

    ~composed_resource() 
    { } 
}; 

मेरे अनुभवहीन जावा समाधान:

public class ComposedResource implements Closeable 
{ 
    private final ResourceA a; 
    private final ResourceB b; 
    private final ResourceC c; 

    public ComposedResource(int x) /* throws ... */ { 
     a = new ResourceA(x); 
     try { 
      b = new ResourceB(x); 
      try { 
       c = new ResourceC(x); 
      } catch (Throwable t) { 
       b.close(); 
       throw t; 
      } 
     } catch (Throwable t) { 
      a.close(); 
      throw t; 
     } 
    } 

    @Override 
    public void close() throws IOException { 
     try { 
      a.close(); 
     } finally { 
      try { 
       b.close(); 
      } finally { 
       c.close(); 
      } 
     } 
    } 
} 

एक थोड़ा सुधार हुआ संस्करण:

public class ComposedResource2 implements Closeable 
{ 
    private final ResourceA a; 
    private final ResourceB b; 
    private final ResourceC c; 

    public ComposedResource2(int x) /* throws ... */ { 
     try { 
      a = new ResourceA(x); 
      b = new ResourceB(x); 
      c = new ResourceC(x); 
     } catch (Throwable t) { 
      close(); 
      throw t; 
     } 
    } 

    @Override 
    public void close() throws IOException { 
     try { 
      if (a != null) a.close(); 
     } finally { 
      try { 
       if (b != null) b.close(); 
      } finally { 
       if (c != null) c.close(); 
      } 
     } 
    } 
} 

वहाँ एक है अधिक सुरुचिपूर्ण समाधान जो अभी भी अपवाद सुरक्षा को बनाए रखते हुए घोंसला वाले प्रयास-पकड़-ब्लॉक से बचाता है? यह तीन संसाधनों के साथ प्रबंधनीय है, लेकिन कुछ और भी अनावश्यक हो रहा है। (यदि यह एक स्थानीय गुंजाइश थी, मैं तो बस एक "ट्राई-साथ-संसाधन" बयान इस्तेमाल कर सकते हैं, लेकिन यह है कि यहाँ लागू नहीं है।)


मैं इस बारे में सोचा java.rmi के साथ काम करते। कन्स्ट्रक्टर में मैं रजिस्ट्री बना रहा/देख रहा हूं, वस्तुओं को देख रहा हूं और ऑब्जेक्ट्स निर्यात कर रहा हूं। क्लोज़() को अनधिकृत और अप्रत्याशित वस्तुओं की आवश्यकता है। मैंने निर्यात/अप्रत्याशित संभालने के लिए रैपर ऑब्जेक्ट्स बनाने के बारे में सोचा (जैसे मैं आरएआईआई का लाभ लेने के लिए सी ++ में करता हूं), लेकिन फिर मैंने देखा कि मुझे बहुत मदद नहीं करेगा (मैं जावा विशेषज्ञ का इतना अधिक नहीं हूं, लेकिन मुझे इसे विश्वविद्यालय के लिए उपयोग करना है)।

फिलहाल मैं ऊपर ComposedResource2 जैसे कुछ का उपयोग कर रहा हूं, और यह ठीक काम करता है। लेकिन अब मुझे यह जानने में दिलचस्पी है कि क्या एक और अधिक सुरुचिपूर्ण समाधान है।

+2

क्या आप एक उपयोग केस पेश कर सकते हैं? हो सकता है कि एक ठोस उदाहरण के साथ काम करना एक अमूर्त समस्या से बेहतर उत्तर देगा ... –

+1

कोशिश-संसाधन नहीं लागू क्यों नहीं है? –

+2

1) रचनाकारों में संसाधन बनाने से बचें - वे, आदर्श रूप से, केवल फ़ील्ड को पैरामीटर असाइन करना चाहिए, और मुझे लगता है कि आरएआईआई यहां लागू नहीं है। 2) यदि संभव हो तो कोशिश-संसाधनों का उपयोग करें (शायद यह आपके लिए अधिक संभव होगा जब आपका कन्स्ट्रक्टर केवल "असाइनमेंट मोड" में काम करेगा)। 3) आप अपना 'बंद करने योग्य' सजावट लिख सकते हैं जो एक ही उदाहरण में एकाधिक 'बंद करने योग्य' उदाहरणों में शामिल होगा। 4) या आप Guava 'com.google.common.io का उपयोग कर सकते हैं।Closer'। –

उत्तर

11

इस तरह के प्रयासों के साथ प्रयास करें।

@Override 
public void close() throws IOException { 
    try (Closeable cc = c; 
     Closeable bb = b; 
     Closeable aa = a;) { 
     // do nothing 
    } 
} 
+0

क्या प्रारंभिक त्रुटियों के कारण संसाधन शून्य है? – AdamSkywalker

+2

@AdamSkywalker यदि बी शून्य था, ए और सी बंद हो जाएगा। – saka1029

+2

@AdamSkywalker 'try-with-resource' जावा में शून्य-सुरक्षित है: भले ही सभी' सीसी', 'बीबी', और 'aa' शून्य हैं - कुछ भी विफल नहीं होता है। इसके अलावा, अनियमित या खराब प्रारंभिक वस्तुओं का उपयोग नहीं किया जाना चाहिए और प्रारंभिक अपवाद फेंकना चाहिए। सबसे अच्छा मामला हमेशा अच्छी तरह से शुरूआती वस्तुओं है। –

1

इस तरह से बंद() को बदलने के बारे में क्या?

@Override 
public void close() { 
    close(a); 
    close(b); 
    close(c); 
} 

public void close(Closeable closeable) throws IOException{ 
     if (closeable != null){ 
      closeable.close(); 
     } 
} 

मुझे लगता है कि इसकी अधिक साफ ...

इसके अलावा, आप 3 संसाधनों 'Closeables' के रूप में प्रबंधन और उन्हें एक सरणी में डाल सकते हैं इसलिए ComposedResource के रूप में आप चाहते हैं के रूप में कई संसाधनों होगा। कुछ इस तरह कर रही है:

ComposedResource c = new ComposedResource(); 
c.add(new Resource1()); 
c.add(new Resource2()); 
c.add(new Resource3()); 
... 
// do nice thinks 
// and, to close; 
c.close(); 

संपादित करें::

@Mohit कंवर अपवाद फेंकने के लिए पता चलता है, कि जिस तरह से:

@Override 
public void close() throws IOException { 
    for (Closeable r : resources){ 
     r.close(r); 
    } 
} 

public class ComposedResource{ 
    List<Closeable> resources = new ArrayList<Closeable>(); 

    public void add(Closeable c){ 
     resources.add(c); 
    } 

    @Override 
    public void close(){ 
     for (Closeable r : resources){ 
      close(r); 
     } 
    } 

    public void close(Closeable c){ 
     try{ 
      c.close(); 
     catch (IOException e){ 
      log(e); 
     } 
    } 
} 

तो तुम संसाधनों जोड़ देगा

और मेरा कोड संपादित किया, @ एलआईआई का कहना है कि यह एक अपवाद करने से सभी संसाधनों को बंद करना बंद हो जाएगा और मैं सहमत हूं वें लिआई इसलिए मैंने मोहित के संपादन को खारिज कर दिया ...

+2

अगर संसाधन बंद नहीं किया जा रहा है, तो लॉगिंग के बाद हम अपवाद फेंकना नहीं चाहिए? –

+3

आपके समाधान में, यदि बंद होने पर पहला संसाधन फेंकता है तो बाद के संसाधन बंद नहीं होंगे। ऐसा नहीं है कि यह कैसे काम करना चाहिए! – Lii

+0

@inigoD मैं इसे अभी समझता हूं। गलत संपादन के लिए मुझे खेद है। मैंने इसके लिए एक ध्वज उठाया है क्योंकि इससे आपको एक डाउनवोट खर्च हुआ है। क्षमा करें :( –

संबंधित मुद्दे