2009-10-20 16 views
54

मेरे पास एक दोस्त है जो जावा में उम्र बढ़ने के बाद .NET विकास में शामिल हो रहा है और उसके कुछ कोड देखने के बाद मुझे लगता है कि वह अक्सर निम्नलिखित कर रहा है:शैली में एक अंतर: IDictionary बनाम शब्दकोश

IDictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>(); 

वह कक्षा के बजाए इंटरफ़ेस के रूप में शब्दकोश घोषित कर रहा है। आमतौर पर मैं निम्नलिखित करना होगा:

Dictionary<string, MyClass> dictionary = new Dictionary<string, MyClass>(); 

मैं केवल IDictionary इंटरफ़ेस का उपयोग होता है, जब यह आवश्यक है (जैसे कि, उदाहरण के लिए एक विधि है कि एक IDictionary इंटरफ़ेस स्वीकार करता है करने के लिए शब्दकोश पारित करने के लिए)।

मेरा प्रश्न है: क्या चीजों को करने के अपने तरीके के लिए कोई योग्यता है? जावा में यह एक आम प्रथा है?

+9

स्थानीय चर के लिए वास्तव में कोई बिंदु नहीं है। – Joren

+0

डुपे: http://stackoverflow.com/questions/1484445/why-are-variables-declared-with-their-interface-name-in-java –

+4

एक अच्छा अभ्यास ** लेकिन ** प्रदर्शन लागत से सावधान रहें: http : //www.nimaara.com/2016/03/06/beware-of-the-idictionary-tkey-tvalue/ – MaYaN

उत्तर

51

यदि IDictionary शब्दकोश से अधिक "अधिक सामान्य" प्रकार है तो यह घोषित करने वाले चर में अधिक सामान्य प्रकार का उपयोग करने के लिए समझ में आता है। इस तरह आपको चर को आवंटित कार्यान्वयन वर्ग के बारे में ज्यादा परवाह नहीं है और आप भविष्य में आसानी से निम्नलिखित कोड को बदलने के बिना आसानी से प्रकार बदल सकते हैं। उदाहरण के लिए, जावा में यह अक्सर बेहतर की तुलना में यह

LinkedList<Integer> intList=new LinkedList<Integer>(); 

इस तरह मुझे यकीन है कि सभी निम्नलिखित कोड एक सूची और नहीं एक LinkedList के रूप में सूची में व्यवहार करता हूँ करना है माना जाता है

List<Integer> intList=new LinkedList<Integer>(); 

करना है, भविष्य में वेक्टर या किसी भी अन्य वर्ग के लिए लिंक्डलिस्ट को स्विच करने के लिए भविष्य में आसान बनाना जो सूची लागू करता है। मैं कहूंगा कि यह जावा के लिए आम है और सामान्य रूप से अच्छा प्रोग्रामिंग है।

+19

+1, लेकिन हो सकता है कि आप चाहें 'जेनेरिक' की बजाय 'सामान्य' शब्द का उपयोग करें, जिसमें पहले से ही संलग्न अर्थ का बाल्टीलोड है :) – AakashM

24

यह अभ्यास जावा तक ही सीमित नहीं है।

यह अक्सर .NET में उपयोग किया जाता है जब आप उस वर्ग से ऑब्जेक्ट का उदाहरण जोड़ना चाहते हैं जिसका आप उपयोग कर रहे हैं। यदि आप कक्षा के बजाय इंटरफ़ेस का उपयोग करते हैं, तो आप अपने शेष कोड को तोड़ने के बिना जब भी आवश्यक हो बैकिंग प्रकार बदल सकते हैं।

आप इस अभ्यास को फैक्टरी पैटर्न का उपयोग करके आईओसी कंटेनर और इंस्टेंसियस से निपटने के साथ भारी रूप से उपयोग करेंगे।

+0

लेकिन आप सभी कार्यक्षमताओं को खो देते हैं जो शब्दकोश प्रदान कर सकते हैं जो आईडीकी में नहीं है। – rein

+8

लेकिन यदि आप इसके बजाय IDictionary का उपयोग करने में सक्षम हैं ... आप प्रारंभ करने के लिए कार्यक्षमता का उपयोग नहीं कर रहे हैं। –

+1

लेकिन अगर आपको केवल आईडीकेरी में कार्यक्षमता की आवश्यकता है ... ID12 के लिए अन्य तरीकों से IDictionary को शब्दकोश में बदलना आसान है :) – Svish

4

जहां तक ​​मैंने देखा है कि जावा डेवलपर्स .NET डेवलपर्स की तुलना में अक्सर अबास्ट्रक्शन (और डिज़ाइन पैटर्न) का उपयोग करते हैं। यह इसका एक और उदाहरण है: कंक्रीट क्लास की घोषणा क्यों करें जब वह अनिवार्य रूप से केवल इंटरफ़ेस सदस्यों के साथ काम करेगा?

+0

मैं दूसरी वाक्य तक आपके साथ था। आप एक इंटरफ़ेस कार्यान्वयन के संदर्भ को और कैसे प्राप्त करना चाहते हैं? आपको कुछ ऐसा करने की ज़रूरत है जो इसे लागू करे। 'नया आईडीआईआर <स्ट्रिंग, डबल>() 'काम नहीं करेगा, और वैसे भी कोई समझ नहीं आता है। –

+0

मैं वास्तव में समझ में नहीं आता ... मेरा मुद्दा यह था कि जो कभी भी डिक्शनरी सदस्य का उपयोग करता है केवल आईडीआईआर क्षमताओं का उपयोग करना चाहता है। जाहिर है आपको कुछ को तत्काल करना है, लेकिन यदि आप इस पैटर्न का उपयोग करते हैं तो निम्नलिखित कोड का अर्थ क्लास का उपयोग करने वाले लोगों के लिए होगा: आईडीकी शब्दकोश = नया शब्दकोश (); और IDictionary शब्दकोश = नया ConcurrentDictionary (); यदि आप डिक्शनरी या कंक्रीट डिक्शनरी विशिष्ट सदस्यों का उपयोग नहीं करेंगे, तो यह समझ में आता है कि उन्हें क्लास वेरिएबल के प्रकार के रूप में घोषित न करना, अबास्ट्रक्शन की एक परत जोड़ना। –

1

मुझे पता चला है कि स्थानीय चर के लिए यह आमतौर पर कोई फर्क नहीं पड़ता कि आप इंटरफ़ेस या कंक्रीट क्लास का उपयोग करते हैं या नहीं।

कक्षा के सदस्यों या विधि हस्ताक्षरों के विपरीत, यदि आप प्रकार बदलने का निर्णय लेते हैं, तो न ही बहुत ही कम रिफैक्टरिंग प्रयास होता है, न ही इसकी उपयोग साइट के बाहर परिवर्तनीय दिखाई देता है। वास्तव में, जब आप स्थानीय लोगों को घोषित करने के लिए var का उपयोग करते हैं, तो आपको इंटरफ़ेस प्रकार नहीं मिल रहा है बल्कि क्लास प्रकार (जब तक आप स्पष्ट रूप से इंटरफ़ेस पर नहीं डाले जाते)।

हालांकि, विधियों, वर्ग के सदस्यों या इंटरफेस घोषित करते समय, मुझे लगता है कि यह सार्वजनिक एपीआई को एक विशिष्ट वर्ग प्रकार के साथ जोड़ने के बजाय इंटरफ़ेस प्रकार के सामने का उपयोग करने के लिए आपको थोड़ा सिरदर्द बचाएगा।

+2

यह मेरी राय भी थी - विधि परिभाषाओं के लिए विधि का पुन: उपयोग करने के बाद सामान्य प्रकार का प्रयास करना और उपयोग करना अधिक महत्वपूर्ण है। स्थानीय चर के लिए मुझे योग्यता दिखाई नहीं दे रही है। – rein

+1

व्यक्तिगत रूप से मुझे लगता है कि योग्यता तथ्य यह है कि आप कार्यान्वयन कक्षाओं पर संभावित निर्भरताओं को आसानी से खोजेंगे। उदाहरण के लिए यदि आप अपने स्थानीय चर को उपयोगिता विधि या किसी चीज़ पर पास करते हैं। – NickDK

+2

स्थानीय चर के लिए, मैंने जो तर्क देखा है, वे हैं 1) यह आपको इंटरफेस का उपयोग करने में अनुशासित रखता है, और 2) यह आपके कोड को फ़ंक्शन कॉल के रिटर्न प्रकारों के प्रति कम संवेदनशील होने की अनुमति देता है जो स्थानीय लोगों को असाइन करते हैं - जिसका अर्थ है कि फ़ंक्शन अपने कोड को प्रभावित किए बिना कंक्रीट प्रकार को बदल सकते हैं (जब तक वापसी का प्रकार अभी भी इंटरफ़ेस का पालन करता है)। – LBushkin

1

इंटरफेस का उपयोग करने का अर्थ है कि निम्नलिखित कोड में "शब्दकोश" IDictionary का कोई कार्यान्वयन हो सकता है।

Dictionary1 dictionary = new Dictionary1(); 
dictionary.operation1(); // if operation1 is implemented only in Dictionary1() this will fail for every other implementation 

यह सबसे अच्छा देखा है जब आप वस्तु के निर्माण को छिपाने:

IDictionary dictionary = DictionaryFactory.getDictionary(...); 
+0

मैं इस बात से सहमत हूं कि एक गैर-विशिष्ट शब्दकोश लौटने के लिए कारखाने का उपयोग करते समय यह एक अच्छा विचार है। – rein

+1

मेरा मतलब यह था कि इंटरफ़ेस का उपयोग करके आप "जेनेरिक" शब्दों में सोचने के लिए मजबूर करते हैं, कक्षाओं के decoupling को लागू करने के लिए (मेरे उदाहरण में शब्दकोश 1 का उपयोग कर विधि को वर्ग की आंतरिक संरचना से परिचित होना चाहिए, इंटरफ़ेस के साथ नहीं) –

12

आपके मित्र बहुत उपयोगी सिद्धांत निम्नलिखित है:

"सार खुद के कार्यान्वयन विवरण से"

+5

लेकिन हम कार्यान्वयन के विवरण से निपट रहे हैं। हम कक्षा में एक इंटरफेस नहीं बना रहे हैं - हम बस एक स्थानीय चर घोषित कर रहे हैं। – rein

+7

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

3

वर्णित स्थिति में लगभग हर जावा डेवलपर चर को घोषित करने के लिए इंटरफ़ेस का उपयोग करेगा। जिस तरह से जावा संग्रह इस्तेमाल कर रहे हैं शायद सबसे अच्छा उदाहरण में से एक है:

Map map = new HashMap(); 
List list = new ArrayList(); 

यह सिर्फ स्थितियों का एक बहुत में ढीला संयोजन सिद्ध लगता।

1

जावा संग्रह में कई कार्यान्वयन शामिल हैं। इसलिए, यह मुझे भविष्य में फिर

List<String> myList = new ArrayList<String>(); 

का उपयोग करने के लिए जब मुझे पता है मैं "MyList" की जरूरत है बस के लिए सुरक्षित धागा होने की

List<String> myList = new Vector<String>(); 

और परिवर्तन करने के लिए इस एक लाइन को बदलने के लिए बहुत आसान है कोड की कोई अन्य पंक्ति नहीं। इसमें गेटर्स/सेटर्स भी शामिल हैं। यदि आप उदाहरण के लिए मानचित्र के कार्यान्वयन की संख्या देखते हैं, तो आप कल्पना कर सकते हैं कि यह अच्छा अभ्यास क्यों हो सकता है। अन्य भाषाओं में, जहां कुछ के लिए केवल कुछ कार्यान्वयन हैं (क्षमा करें, एक बड़ा .NET लड़का नहीं) लेकिन उद्देश्य-सी में वास्तव में केवल NSDictionary और NSMutableDictionary है। तो, यह ज्यादा समझ में नहीं आता है।

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

मेरी प्रमुख बिंदु (बस गेटर/setters के साथ यह उल्लेख) में से एक पर हिट करने में विफल।

ऊपर आप की अनुमति देता है:

public void setMyList(List<String> myList) { 
    this.myList = myList; 
} 

और ग्राहक इस कॉल का उपयोग अंतर्निहित कार्यान्वयन के बारे में चिंता की जरूरत नहीं है। सूची इंटरफ़ेस के अनुरूप होने वाली किसी ऑब्जेक्ट का उपयोग करना।

+0

उस पंक्ति को बदलने के लिए: वेक्टर myList = नया वेक्टर (); केवल एक लाइन बदल रहा है। – tster

+0

@tster - लेकिन अन्य कोड कॉल विधियों जो ArrayList के लिए विशिष्ट हैं जिन्हें बदलना होगा क्योंकि वेक्टर के पास एक ही विधि नहीं है? –

+0

सार्वजनिक शून्य सेट MyList (सूची सूची) { myList = सूची; } मान्य है, जब इसे एक सूची के रूप में घोषित किया जाता है, तो प्रत्यक्ष कार्यान्वयन का उपयोग करते समय नहीं। अर्थात। एक ग्राहक आपके कार्यान्वयन में परिवर्तित होने के बारे में चिंता किए बिना जो भी सूची हो सकता है उसका उपयोग कर सकता है। – MarkPowell

1

मुझे जावा डेवलपर के साथ एक ही स्थिति का सामना करना पड़ा है। वह संग्रह और वस्तुओं को उनके इंटरफेस में उसी तरह से तत्काल करता है। उदाहरण के लिए,

IAccount account = new Account(); 

गुण हमेशा/इंटरफेस के रूप में तैयार हो जाओ रहे हैं। इससे क्रमशः here

+1

यह "जादू" धारावाहिकता के साथ केवल एक समस्या है जो .NET वेब सेवा इंटरफेस पर उपयोग करता है। कंक्रीट कक्षाओं के बजाय इंटरफेस का उपयोग करने का अभ्यास पूरी तरह से ध्वनि है। –

+0

हमें विशेष रूप से एएसपी.NET 1.1 –

4

अधिकतर, आप बाहरी कोड के संपर्क में आने पर इंटरफ़ेस प्रकार (IDictionary) का उपयोग करते हैं, चाहे वह असेंबली के बाहर हो या कक्षा के बाहर हो। आम तौर पर, अधिकांश डेवलपर्स इंटरफ़ेस प्रकार का उपयोग करते हुए एक encapsulated संपत्ति का पर्दाफाश करते हुए आंतरिक रूप से एक वर्ग परिभाषा के लिए ठोस प्रकार का उपयोग करते हैं। इस तरह, वे ठोस प्रकार की क्षमताओं का लाभ उठा सकते हैं, लेकिन यदि वे ठोस प्रकार को बदलते हैं, तो घोषित कक्षा के इंटरफ़ेस को बदलने की आवश्यकता नहीं है।

 
public class Widget 
{ 
    private Dictionary<string, string> map = new Dictionary<string, string>(); 
    public IDictionary<string, string> Map 
    { 
     get { return map; } 
    } 
} 

बाद में बन सकता है:

 

class SpecialMap<TKey, TValue> : IDictionary<TKey, TValue> { ... } 

public class Widget 
{ 
    private SpecialMap<string, string> map = new SpecialMap<string, string>(); 
    public IDictionary<string, string> Map 
    { 
     get { return map; } 
    } 
} 

विजेट के इंटरफ़ेस बदल रहा है और पहले से ही इसे प्रयोग अन्य कोड को बदलने के लिए बिना।

7

आपको हमेशा ठोस वर्ग की बजाय इंटरफ़ेस में प्रोग्राम करने का प्रयास करना चाहिए।

जावा या किसी अन्य ऑब्जेक्ट उन्मुख प्रोग्रामिंग भाषा में।

.NET दुनिया में I का उपयोग करना आम है यह इंगित करने के लिए कि यह एक इंटरफेस है जिसका आप उपयोग कर रहे हैं। मुझे लगता है कि यह अधिक आम है क्योंकि सी # में उनके पास कक्षा बनाम इंटरफ़ेस विरासत को संदर्भित करने के लिए implements और extends नहीं है।

मुझे लगता है कि मट्ठा

class MyClass:ISome,Other,IMore 
{ 
} 

टाइप करेंगे और आप बता सकते हैं ISome एक IMore इंटरफेस रहे हैं, जबकि Other एक वर्ग है

जावा में ऐसी बात के लिए कोई जरूरत नहीं है

class MyClass extends Other implements Some, More { 
} 

अवधारणा अभी भी लागू होती है, आपको इंटरफ़ेस को कोड करने का प्रयास करना चाहिए।

+2

में व्यूस्टेट क्रमबद्धता के साथ समस्या आई है, मुझे नहीं लगता कि उसका सवाल यह था कि कैसे इंटरफेस या काम या वे क्यों शुरू होते हैं। इसके अलावा, आधार वर्गों को इंटरफेस से पहले घोषित किया जाना चाहिए। तो, 'पब्लिक क्लास माई क्लास: बेस क्लास, आईफर्स्ट इंटरफेस, आईएसकॉन्डइंटरफेस' सही होगा। एक इंटरफ़ेस की शुरुआत में मेरे बारे में स्वाभाविक रूप से विशेष कुछ भी नहीं है। कंपाइलर इसका अलग-अलग व्यवहार नहीं करता है। यह अन्य प्रोग्रामर के लिए एक मार्कर है। आप उनके बिना अपने इंटरफेस का नाम दे सकते हैं। । । लेकिन अन्य प्रोग्रामर शायद आपको नफरत करेंगे। – tandrewnichols

4

स्थानीय चर और निजी क्षेत्रों के लिए, जो पहले ही कार्यान्वयन के विवरण हैं, घोषणाओं के लिए इंटरफेस की तुलना में कंक्रीट प्रकारों का उपयोग करना बेहतर है क्योंकि ठोस वर्ग प्रदर्शन प्रदर्शन प्रदान करते हैं (प्रत्यक्ष प्रेषण आभासी/इंटरफ़ेस प्रेषण से तेज़ है)। यदि आप अनावश्यक रूप से स्थानीय कार्यान्वयन विवरण में इंटरफ़ेस प्रकारों को नहीं डालते हैं तो जेआईटी अधिक आसानी से इनलाइन विधियों में सक्षम हो जाएगा। यदि एक ठोस प्रकार का एक उदाहरण एक विधि से लौटाया जाता है जो एक इंटरफ़ेस देता है, तो कास्ट स्वचालित होता है।

+4

यह एक माइक्रो-ऑप्टिमाइज़ेशन है जिसे केवल तभी किया जाना चाहिए जब आपके पास हल करने के लिए एक विशिष्ट प्रदर्शन बाधा है, इसे डिज़ाइन ड्राइव नहीं करना चाहिए। – Yishai

+4

यह माइक्रो-ऑप्टिमाइज़ेशन नहीं है। आप पहले ही कार्यान्वयन में हैं जहां आपने ठोस कार्यान्वयन चुना है। क्यों प्रदर्शन करते हैं कि प्रदर्शन की कीमत पर नहीं है? –

3

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

+1

जब तक भविष्य की आवश्यकता अनुबंध की हस्ताक्षर में कोई नई संपत्ति या विधि में परिवर्तन न हो। –

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