2010-09-21 13 views
5

चलें कहते हैं कि हम एक कार्यक्रम है जो इस तरह की कक्षाओं में शामिल है:, सहीजावा संग्रह सहप्रसरण समस्या

public interface AbstractItem { 
} 
public SharpItem implements AbstractItem { 
} 
public BluntItem implements AbstractItem { 
} 

public interface AbstractToolbox { 
    //well the problem starts here... 
    public List<AbstractItem> getItems(); 
} 
public ExpensiveToolbox implements AbstractToolbox { 
    private List<SharpItem> items = new ArrayList()<SharpItems>; 
    public List<SharpItem> getItems() { return this.items; } 
} 
public CheapTooblox implements AbstractToolbox { 
    private List<BluntItem> items = new ArrayList()<BluntItem>; 
    public List<BluntItem> getItems() { return this.items; } 
} 

आसान? खैर कहना अब हम इस तरह एक विधि बनाने के लिए (कुछ यादृच्छिक कक्षा में) चाहते हैं कर सकते हैं:

public void doImportantStuff(AbstractToolbox toolbox) { 
//important stuff! 
//this obviously won't work 
    List<AbstractToolbox> items = toolbox.getItems(); 
//do some stuffwith all items 
} 

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

क्या ऐसी समस्याओं से निपटने के लिए कोई डिज़ाइन पैटर्न/प्रथाएं हैं?

@Edit: ठीक है तो मैं सटीक पर्याप्त नहीं हो सकता है। मैं सारणीटूल को विस्तारित करने वाले कुछ वर्गों की सूची रखने के लिए सार तत्वों को चाहता हूं जो सार तत्वों का विस्तार करते हैं और फिर मुझे एक विधि चाहिए जो पैरामीटर के रूप में एक सारूलूलबॉक्स ले लेगा और इसकी सूची में वस्तुओं पर कुछ करे (कक्षाओं का उपयोग करके परिभाषित किया जाएगा सार तत्व इसलिए सभी संभावित सूची के सभी आइटम वास्तव में उन्हें होंगे)।

+0

स्पष्ट करने के लिए होगा आप अपने doImportantStuff करना चाहते हैं नहीं: सूची आइटम = toolbox.getIems(); – MikeTheReader

+0

आपका क्या मतलब है, "आसान, सही?" आपका पहला खंड संकलित नहीं करता है, और नहीं करना चाहिए! –

+1

ठीक है मुझे लगा कि एसओ के लिए यह आसान होगा। मेरा मतलब है कि * मुझे * इसमें समस्याएं हैं;) –

उत्तर

16

आप शायद जेनरिक के लिए वाइल्डकार्ड प्रकार का उपयोग पर एक नज़र लेने की जरूरत जा रहे हैं। यहां एक त्वरित लिंक है: What is PECS (Producer Extends Consumer Super)?

त्वरित जवाब: List<? extends AbstractItem>

के प्रकार बदलने के आप क्यों नहीं बस इस असाइन नहीं कर सकते?

कोड यहाँ कल्पना कीजिए ...

List<AbstractItem> foo = new ArrayList<SharpItem>(); 
foo.add(new BluntItem()); 

स्थिर टाइपिंग कहना है कि यह काम करना चाहिए ... लेकिन आप ऐसा नहीं कर सकते! यह ArrayList के प्रकार का उल्लंघन करेगा। यही कारण है कि यह अस्वीकृत है। आप

List<? extends AbstractItem> foo = new ArrayList<SharpItem>(); 

के लिए इसे बदल अगर तुम तो काम कर सकते हैं, लेकिन सूची में कुछ भी जोड़ने कभी नहीं। हालांकि, आप अभी भी सूची से तत्व पुनर्प्राप्त कर सकते हैं, हालांकि, सार तत्वों के रूप में।

सिर्फ सूची एक अच्छा समाधान का उपयोग कर (नंगे प्रकार) है?

नहीं है, निश्चित रूप से

+3

या, वैकल्पिक रूप से, टाइप पैरामीटर के साथ AbstractToolbox टाइप करें <टी सार तत्व Item> और इसके बजाय इसका उपयोग करें। –

+0

लेकिन फिर जब आप एक सारटूलबॉक्स स्वीकार करते हैं तो आपको या तो पैरामीटर टी या वाइल्डकार्ड * से निपटने की आवश्यकता होती है *। यदि आपको केवल सार तत्वों से निपटना है, तो इसमें अच्छी संपत्ति है कि आपको कोड के अन्य हिस्सों में टाइप पैरामीटर जोड़ने की आवश्यकता नहीं है। –

+0

इसे प्यार करो, धन्यवाद! –

4

यहाँ :-P नहीं अतिरिक्त विचारों के एक जोड़े हैं। सब कुछ एक ही छोड़ दो, लेकिन इस का उपयोग करें:

interface AbstractToolbox { 
    public List<? extends AbstractItem> getItems(); 
} 

यह मूलतः का कहना है कि अमूर्त वर्ग 'आइटम एक अज्ञात प्रकार हैं, लेकिन उपवर्गों यह ठोस बना सकते हैं। इसके लिए आपको getItems() को किसी प्रकार की सूची पुनर्प्राप्त करने में सक्षम होने के लिए ExpensiveToolbox या CheapToolbox के संदर्भ पर कॉल करने की आवश्यकता होगी जो आपको आइटम जोड़ने आदि की अनुमति देता है।

ExpensiveToolbox toolbox = new ExpensiveToolbox(); 
AbstractToolbox absTB = toolbox; 

List<? extends AbstractItem> items1 = absTB.getItems(); //fine 
List<SharpItem> items2 = absTB.getItems(); //compile error 
List<SharpItem> items3= toolbox.getItems(); //fine 

वैकल्पिक रूप से, तुम सिर्फ टाइप कर सकते हैं AbstractToolbox:

public interface AbstractToolbox<T extends AbstractItem> { 
    public List<T> getItems(); 
} 
public ExpensiveToolbox implements AbstractToolbox<SharpItem> { 
    public List<SharpItem> getItems() { //... 
} 
+0

+1 सार तत्वबॉक्स टाइप करने के लिए, मुझे लगता है कि यह स्पष्ट समाधान है। –

0
public interface AbstractItem 
{ 
} 
public class SharpItem implements AbstractItem 
{ 
} 
public class BluntItem implements AbstractItem 
{ 
} 

public interface AbstractToolbox<T extends AbstractItem> 
{ 
    public List<T> getItems(); 
} 
public class ExpensiveToolbox implements AbstractToolbox<SharpItem> 
{ 
    private List<SharpItem> items = new ArrayList<SharpItem>(); 
    public List<SharpItem> getItems() { return this.items; } 
} 
public class CheapToolbox implements AbstractToolbox<BluntItem> 
{ 
    private List<BluntItem> items = new ArrayList<BluntItem>(); 
    public List<BluntItem> getItems() { return this.items; } 
} 


public void doImportantStuff(AbstractToolbox<?> toolbox) 
{ 
    List<? extends AbstractItem> items = toolbox.getItems(); 

    for(AbstractItem item : items) 
     ... ; 

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