यह अभी तक उन भाषा डिजाइन मुद्दों में से एक है जो "स्पष्ट रूप से एक अच्छा विचार" लगता है जब तक आप खुदाई शुरू नहीं करते हैं और आपको पता चलता है कि वास्तव में यह एक बुरा विचार है।
इस मेल में इस विषय पर बहुत कुछ है (और अन्य विषयों पर भी।) कई डिजाइन बल थे जो हमें वर्तमान डिजाइनों में लाने के लिए अभिसरित थे:
- विरासत मॉडल को सरल रखने की इच्छा;
- तथ्य यह है कि एक बार जब आप स्पष्ट उदाहरणों को देखते हैं (उदाहरण के लिए,
AbstractListएक इंटरफ़ेस में बदलना ), तो आपको एहसास होता है कि विरासत में मिला समान / हैशकोड /String दृढ़ता से एकल विरासत और स्थिति से जुड़ा हुआ है, और इंटरफेस बहुतायत से विरासत में मिले हैं और स्टेटलेस हैं;
- कि इसने संभावित रूप से कुछ आश्चर्यजनक व्यवहारों के लिए दरवाजा खोल दिया।
आपने पहले से ही "इसे सरल रखें" लक्ष्य पर छुआ है; इनहेरिटेंस और संघर्ष-रिज़ॉल्यूशन के नियमों को बहुत सरल बनाया गया है (कक्षाएं इंटरफेस पर जीत हासिल करती हैं, व्युत्पन्न इंटरफेस सुपरएन्थफेसेस पर जीतते हैं, और किसी भी अन्य संघर्ष को कार्यान्वयन वर्ग द्वारा हल किया जाता है।) बेशक इन नियमों को एक अपवाद बनाने के लिए ट्वीक किया जा सकता है, लेकिन। मुझे लगता है कि जब आप उस तार को खींचना शुरू करेंगे, तो आप पाएंगे कि वृद्धिशील जटिलता उतनी छोटी नहीं है जितना आप सोच सकते हैं।
बेशक, वहाँ लाभ के कुछ डिग्री है कि अधिक जटिलता का औचित्य साबित होगा, लेकिन इस मामले में यह नहीं है। हम यहां जिन तरीकों के बारे में बात कर रहे हैं, वे समान हैं, हैशकोड और स्ट्रींग। वस्तु स्थिति के बारे में ये सभी तरीके आंतरिक हैं, और यह वह वर्ग है जो राज्य का मालिक है, इंटरफ़ेस नहीं, जो यह निर्धारित करने के लिए सबसे अच्छी स्थिति में है कि उस वर्ग के लिए समानता का क्या मतलब है (विशेषकर समानता के लिए अनुबंध काफी मजबूत है; प्रभावी देखें) कुछ आश्चर्यजनक परिणामों के लिए जावा); इंटरफ़ेस लेखक अभी बहुत दूर हैं।
AbstractListउदाहरण को बाहर निकालना आसान है ; यह प्यारा होगा यदि हम छुटकारा पा सकते हैं AbstractListऔर Listइंटरफ़ेस में व्यवहार डाल सकते हैं । लेकिन एक बार जब आप इस स्पष्ट उदाहरण से आगे बढ़ जाते हैं, तो कई अन्य अच्छे उदाहरण नहीं मिलते हैं। मूल रूप से, AbstractListएकल वंशानुक्रम के लिए डिज़ाइन किया गया है। लेकिन इंटरफेस को कई विरासत के लिए डिज़ाइन किया जाना चाहिए।
इसके अलावा, कल्पना कीजिए कि आप इस वर्ग को लिख रहे हैं:
class Foo implements com.libraryA.Bar, com.libraryB.Moo {
// Implementation of Foo, that does NOT override equals
}
FooSupertypes पर लेखक दिखता है, बराबरी का कोई कार्यान्वयन देखता है, और है कि संदर्भ समानता प्राप्त करने के लिए निष्कर्ष निकाला है, सभी वह जरूरत से विरासत बराबर है Object। फिर, अगले सप्ताह, बार "मददगार" के लिए पुस्तकालय अनुरक्षक एक डिफ़ॉल्ट equalsकार्यान्वयन जोड़ता है । ओह! अब Fooएक अन्य रखरखाव डोमेन "सहायक रूप से" एक सामान्य विधि के लिए एक डिफ़ॉल्ट जोड़कर एक इंटरफ़ेस द्वारा शब्दार्थ को तोड़ दिया गया है।
चूक को चूक माना जाता है। एक इंटरफ़ेस में डिफ़ॉल्ट जोड़ना जहां कोई नहीं था (पदानुक्रम में कहीं भी) कंक्रीट कार्यान्वयन कक्षाओं के शब्दार्थ को प्रभावित नहीं करना चाहिए। लेकिन अगर चूक वस्तु विधियों को "ओवरराइड" कर सकती है, तो यह सच नहीं होगा।
इसलिए, जबकि यह एक हानिरहित विशेषता की तरह लगता है, यह वास्तव में काफी हानिकारक है: यह थोड़ा वृद्धिशील अभिव्यक्ति के लिए बहुत अधिक जटिलता जोड़ता है, और यह सुविचारित, हानिरहित दिखने वाले बदलावों को अलग-अलग करने के लिए अलग इंटरफेस को कम करने के लिए बहुत आसान बनाता है। कक्षाओं को लागू करने के इरादे का अर्थ।