2010-07-28 19 views
8

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

मानते हैं कि कक्षा पशु अमूर्त वर्ग है।

public class AnimalReference 
{ 
    public static void main(String args[]) 
    Animal ref     // set up var for an Animal 
    Cow aCow = new Cow("Bossy"); // makes specific objects 
    Dog aDog = new Dog("Rover"); 

    // now reference each as an Animal 
    ref = aCow; ref.speak(); 
    ref = aDog; ref.speak(); 
} 

मैं की तरह ArrayList के उदाहरण बनाने के लिए इस्तेमाल:

ArrayList myList = new ArrayList(); 

लेकिन आम तौर पर मैं लगा कि लोगों को लिखें:

Collection myList = new ArrayList(); 

तो मेरी भ्रम क्या संग्रह के रूप में घोषित करने के लाभ है ? इसके अलावा मुझे नहीं पता था कि "MyList" के सामने आपके पास "संग्रह" (जो एक इंटरफ़ेस नहीं है) श्रेणी हो सकता है।

क्यों यह अच्छा अभ्यास नहीं है सिर्फ इतना कहना है:

ArrayList myList = new ArrayList(); 

मैं संग्रह इंटरफेस और ArrayList जावा दस्तावेजों के साथ ही ऑनलाइन ट्यूटोरियल पढ़ा है लेकिन अभी भी वास्तव में स्पष्ट नहीं .. किसी को भी मुझे कुछ स्पष्टीकरण देने सकते हैं?

उत्तर

10

यदि आप myList को ArrayList के रूप में घोषित करते हैं, तो आप इसके ठोस प्रकार को ठीक करते हैं।इसका उपयोग करने वाले प्रत्येक व्यक्ति इस ठोस प्रकार पर निर्भर करेगा, और कॉल विधियों (यहां तक ​​कि अनजाने में) कॉल करना आसान है जो ArrayList के लिए विशिष्ट हैं। अगर कुछ समय बाद आप इसे बदलना तय करते हैं उदा। LinkedList या CopyOnWriteArrayList, आपको पुन: संकलित करने की आवश्यकता है - और संभवतः यहां तक ​​कि क्लाइंट कोड भी बदलना होगा। इंटरफेस के लिए प्रोग्रामिंग इस जोखिम को समाप्त करता है।

ध्यान दें कि Collection और ArrayList के बीच, अमूर्तता का एक और स्तर है: List इंटरफ़ेस। आम तौर पर किसी सूची का उपयोग पैटर्न मानचित्र, सेट या कतार से बहुत अलग होता है। इसलिए आपको नौकरी के लिए आवश्यक संग्रह का प्रकार आमतौर पर तय किया जाता है, और यह बदलने वाला नहीं है। List के रूप में अपने चर को घोषित करने से यह निर्णय स्पष्ट हो जाता है, और इस संग्रह के अनुबंध के संबंध में अपने ग्राहकों को उपयोगी जानकारी देता है। Collection ओटीओएच आमतौर पर इसके तत्वों के माध्यम से पुनरावृत्ति से अधिक के लिए बहुत उपयोगी नहीं है।

0

CollectionArrayList का एक सुपरटेप है। यदि आपको केवल Collection द्वारा प्रदान की गई कार्यक्षमता की आवश्यकता है, तो यह अच्छी प्रथा है क्योंकि आप स्पष्ट रूप से इंगित कर रहे हैं कि आपको घोषणा परिवर्तनीय में किस कार्यक्षमता की आवश्यकता है। प्रारंभिक में ArrayList चुनने के लिए आप अप्रासंगिक हैं (हालांकि एक अच्छी डिफ़ॉल्ट पसंद); घोषणा है कि यह Collection आपको और भविष्य के कोडर को बताता है कि आप किस अनुबंध के बारे में परवाह करते हैं।

+0

कृपया विस्तार करें कि यह क्यों अच्छा अभ्यास है। –

+0

@ जैकोब टॉमॉ यह अच्छा अभ्यास है क्योंकि आप स्पष्ट रूप से संकेत दे रहे हैं कि आपको चर _declaration_ में किस कार्यक्षमता की आवश्यकता है। कि आप _initialization_ में 'ArrayList' चुनते हैं अप्रासंगिक है (हालांकि एक अच्छी डिफ़ॉल्ट पसंद); यह घोषणा कि यह 'संग्रह' है, आपको और भविष्य के कोडर को बताता है कि आप किस अनुबंध के बारे में सोचते हैं। –

+0

आप अपने जवाब को नाटकीय रूप से सुधार सकते हैं जिसमें जवाब देने के बजाय उत्तर में यह पता चलता है कि हर कोई जानता है कि यह अच्छा अभ्यास क्यों है। मुझे लगता है कि इस प्रश्न को पढ़ने वाले अधिकांश लोगों के पास आपके पास अनुभव नहीं होगा। –

0

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

+1

'मानचित्र' 'संग्रह' को विस्तार/कार्यान्वित नहीं करता है। – Powerlord

+0

अच्छा बिंदु। मुझे आशा है कि बिंदु अभी भी खड़ा है, हालांकि :) – Gian

+1

क्या आप जानते हैं कि आप अपना उत्तर संपादित कर सकते हैं? – DJClayworth

3

यदि आप ArrayList घोषित कर रहे हैं, तो मैं कभी भी बाईं ओर वाले प्रकार के रूप में ArrayList का उपयोग नहीं करता। इसके बजाय, इंटरफ़ेस पर प्रोग्राम, List या Collection हो।

ध्यान दें कि यदि आप Collection लेने के तरीके को घोषित करते हैं, तो इसे List या Set पारित किया जा सकता है।

एक साइड नोट के रूप में, Generics का उपयोग करने पर विचार करें।

संपादित करें: यह कहकर, जेनरिक कुछ गॉटचा भी पेश करता है।

List<Animal> एक ArrayList<Animal> संग्रहीत कर सकती है, लेकिन नहीं एक ArrayList<Cat>ArrayList<Cat> स्टोर करने के लिए आपको List<? extends Animal> की आवश्यकता होगी।

4

Collection का उपयोग करने के बजाय List<Something> myList = new ArrayList<Something>(); लिखना शायद अधिक आम है। आमतौर पर इसकी सूची के कुछ पहलू महत्वपूर्ण हैं। डुप्लिकेट तत्वों को स्वीकार करने के संबंध में Collection की अस्पष्टता चाहे वह एक सेट या सूची (या जो कुछ भी) हो, दर्द हो सकती है।

उस तरफ, प्राथमिक उद्देश्य अमूर्तता या कार्यान्वयन स्वतंत्रता है। क्या मुझे वास्तव में परवाह है कि मेरी सूची में ArrayList या Vector है? शायद ज्यादातर समय नहीं। मेरा कोड अधिक लचीला है यदि यह सबसे सामान्य इंटरफ़ेस का उपयोग करता है जो व्यक्त करता है कि मुझे ऑब्जेक्ट की क्या ज़रूरत है।

आसान उदाहरण है, आप सभी ArrayList s का उपयोग करके एक प्रोग्राम लिखने लगता है, और फिर बाद में यह, अधिक उपयोगकर्ताओं का समर्थन करने की जरूरत है ताकि धागा सुरक्षा के लिए आप Vecto रु के लिए अपने सभी ArrayList रों बदलना चाहते हैं। यदि आप टाइप ArrayList के संदर्भों के आसपास गुजर रहे हैं, तो आपको हर जगह हर उपयोग को बदलना होगा। यदि आप टाइप List के संदर्भों के आसपास गुजर रहे हैं, तो आपको केवल उन स्थानों को बदलना होगा जहां आप उन्हें बनाते हैं।

इसके अलावा, कभी-कभी कार्यान्वयन वर्ग ऐसा कुछ भी नहीं हो सकता है जिसे आप आयात या उपयोग करना चाहते हैं। उदाहरण के लिए, जब हाइबरनेट जैसे दृढ़ता प्रदाता का उपयोग करते हैं, तो वास्तविक वर्ग जो Set इंटरफ़ेस लागू करता है, ढांचे के लिए अद्वितीय एक अत्यधिक विशिष्ट कस्टम कार्यान्वयन हो सकता है, या ऑब्जेक्ट कैसे बनाया गया है, इस पर निर्भर करता है कि यह पुराना HashSet हो सकता है। आपको अंतर की परवाह नहीं है, यह सिर्फ आपके लिए Set है।

1

सबसे पहले विरासत और इंटरफेस के बीच एक महत्वपूर्ण अंतर है। एक छोटी सी यात्रा वापस इतिहास: सादे पुराने सी ++ में जहां आप कई कक्षाओं से उत्तराधिकारी हो सकते हैं। इसका नकारात्मक परिणाम हुआ अगर "ट्रांसफॉर्मर" वर्ग "वाहन" और "मानव" से प्राप्त होता है, तो दोनों "MoveForward" नामक विधि को कार्यान्वित करते हैं। अगर आप इस विधि को "ट्रांसफार्मर" वर्ग पर कॉल करते हैं तो उदाहरण का उपयोग किस प्रकार किया जाता है? "मानव" या "वाहन" कार्यान्वयन? इस समस्या को हल करने के लिए जावा, सी #, ... द्वारा इंटरफेस पेश किए जाते हैं। इंटरफेस आपके वर्ग और कुछ और के बीच एक अनुबंध है। आप कार्यक्षमता के लिए एक प्रतिबद्धता है, लेकिन अनुबंध अपनी कक्षा के लिए किसी भी तर्क को लागू नहीं करता है (Transformer.MoveForward को रोकने के लिए "समस्या)।

सामान्य रूप में बहुरूपता का मतलब है कि कुछ अलग रूपों में दिखाई दे सकते हैं। एक" ट्रांसफार्मर "हो सकता है एक "वाहन" और "मानव"। आप जिस भाषा को पूरा करना चाहते हैं उसके आधार पर आप "मूवफॉरवर्ड" के लिए अलग-अलग व्यवहार लागू कर सकते हैं।

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

उम्मीद है कि यह इंटरफेस के फायदे को थोड़ा सा समझने में मदद करता है।

1

जिस प्रकार आप स्थानीय परिवर्तनीय घोषणा में उपयोग करते हैं (जैसा कि आपके ऐरेलिस्ट उदाहरण में) आमतौर पर महत्वपूर्ण नहीं है। आपको यह सुनिश्चित करना होगा कि है कि MyList (नाम 'myList' नाम के बाईं ओर वाला शब्द) myList लेता है जो किसी भी विधि पैरामीटर के प्रकार से अधिक विशिष्ट होने के लिए है।

पर विचार करें:

ArrayList words = new ArrayList(); 
sort(words); 
removeNames(words); 

public void sort(Collection c) ... blah blah blah 

public void removeNames(List words) ... 

मैं सिर्फ सूची होने के लिए 'शब्द' के प्रकार प्रतिस्थापित किया जा सकता था। यह पठनीयता या मेरे कार्यक्रम के व्यवहार में कोई फर्क नहीं पड़ता है। हालांकि मैं ऑब्जेक्ट होने के लिए 'शब्दों' को परिभाषित नहीं कर सका। यह बहुत सामान्य है।

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

ArrayList words = new ArrayList(); 

// this line will cause a compilation error. 
sort(words); 

public void sort(LinkedList c) ... blah blah blah 

तरह की परिभाषा अब बहुत ही सीमित है। पहले उदाहरण में, सॉर्ट विधि किसी ऑब्जेक्ट को पैरामीटर के रूप में अनुमति देती है, जब तक कि यह संग्रह लागू करता है। दूसरे उदाहरण में, सॉर्ट केवल लिंक्डलिस्ट की अनुमति देता है, यह किसी और चीज को स्वीकार नहीं करेगा (ArrayLists, हैशसेट्स, ट्रीसेट्स और कई अन्य)। जिन परिदृश्यों में का उपयोग किया जा सकता है, वे परिदृश्य अब काफी सीमित हैं। यह अच्छे कारण के लिए हो सकता है; सॉर्ट का कार्यान्वयन LinkedList डेटा संरचना की सुविधा पर भरोसा कर सकता है। अगर का उपयोग करने वाले लोग इस कोड को सॉर्ट करना चाहते हैं तो यह कोड केवल एक प्रकार का एल्गोरिदम चाहता है जो लिंक्डलिस्ट के अलावा अन्य चीज़ों के लिए काम करता है।

जावा पुस्तकालयों को लिखने में मुख्य कौशल में से एक विधि पैरामीटर के के प्रकार का निर्णय ले रहा है। आप कितने सामान्य बनना चाहते हैं?

1

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

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

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