क्या इंटरफ़ेस का पूरा बिंदु नहीं है कि कई वर्ग नियमों और कार्यान्वयनों के एक समूह का पालन करते हैं?
क्या इंटरफ़ेस का पूरा बिंदु नहीं है कि कई वर्ग नियमों और कार्यान्वयनों के एक समूह का पालन करते हैं?
जवाबों:
सख्ती से, नहीं, तुम नहीं, YAGNI लागू होता है। उस ने कहा, इंटरफ़ेस बनाने में आप जो समय बिताएंगे, वह न्यूनतम है, खासकर यदि आपके पास एक आसान कोड जनरेशन टूल है, जो आपके लिए अधिकांश काम कर रहा है। यदि आप इस बात पर अनिश्चित हैं कि आपको इंटरफ़ेस की आवश्यकता है या नहीं, तो मैं कहूंगा कि इंटरफ़ेस की परिभाषा का समर्थन करने की दिशा में गलत करना बेहतर होगा।
इसके अलावा, एक वर्ग के लिए भी एक इंटरफेस का उपयोग करना आपको यूनिट परीक्षणों के लिए एक और नकली कार्यान्वयन प्रदान करेगा, जो उत्पादन पर नहीं है। अवनर शाहर-कश्तन का जवाब इस बिंदु पर है।
मैं जवाब दूंगा कि आपको एक इंटरफ़ेस की आवश्यकता है या नहीं यह इस बात पर निर्भर नहीं करता है कि कितने वर्ग इसे लागू करेंगे। इंटरफेस आपके आवेदन के कई उप-प्रणालियों के बीच अनुबंध को परिभाषित करने के लिए एक उपकरण है ; तो वास्तव में क्या मायने रखता है कि आपके आवेदन को उपतंत्रों में कैसे विभाजित किया गया है। इनकैप्सुलेटेड सबसिस्टम के सामने के अंत के रूप में इंटरफेस होना चाहिए, चाहे कितनी भी कक्षाएं उन्हें लागू करें।
यहाँ एक बहुत ही उपयोगी नियम है:
Foo
सीधे कक्षा के संदर्भ में बनाते हैं BarImpl
, तो आप Foo
हर बार बदलने के लिए खुद को बदलने के लिए दृढ़ता से प्रतिबद्ध हैं BarImpl
। आप मूल रूप से उन्हें कोड की एक इकाई के रूप में मान रहे हैं जो दो वर्गों में विभाजित है।Foo
को संदर्भित करते हैं, तो जब आप बदलते हैं तो परिवर्तनों से बचने के लिए आप स्वयं को कमिट कर रहे हैं । Bar
Foo
BarImpl
यदि आप अपने आवेदन के प्रमुख बिंदुओं पर इंटरफेस को परिभाषित करते हैं, तो आप उन तरीकों के बारे में सावधानीपूर्वक विचार करें, जिनका उन्हें समर्थन करना चाहिए और जो उन्हें नहीं करना चाहिए, और आप इंटरफेस को स्पष्ट रूप से वर्णन करते हैं कि कार्यान्वयन कैसे व्यवहार करना चाहिए (और कैसे नहीं), आपके आवेदन को समझने के लिए, क्योंकि इन टिप्पणी की इंटरफेस का एक प्रकार प्रदान करेगा एक बहुत आसान हो जाएगा विनिर्देश आवेदन-एक है कि यह कैसे है के विवरण की इरादा व्यवहार करने के लिए। इससे कोड को पढ़ने में बहुत आसान हो जाता है (यह पूछने के बजाय "क्या बिल्ली इस कोड को करना है" आप पूछ सकते हैं "यह कोड कैसे करता है जो यह करना है")।
इस सब के अलावा (या वास्तव में इसकी वजह से), इंटरफेस अलग संकलन को बढ़ावा देते हैं। चूंकि इंटरफेस संकलन के लिए तुच्छ होते हैं और उनके कार्यान्वयन की तुलना में कम निर्भरता होती है, इसका मतलब है कि यदि आप Foo
इंटरफ़ेस का उपयोग करने के लिए क्लास लिखते हैं Bar
, तो आप आमतौर पर फिर से शुरू BarImpl
करने की आवश्यकता के बिना पुनरावृत्ति कर सकते हैं Foo
। बड़े अनुप्रयोगों में यह बहुत समय बचा सकता है।
Foo
इंटरफ़ेस पर निर्भर करता है, Bar
तो BarImpl
बिना रीकॉम्पेल किए संशोधित किया जा सकता है Foo
। 4. सार्वजनिक / निजी ऑफ़र की तुलना में महीन-महीन एक्सेस कंट्रोल (एक ही क्लास को दो क्लाइंट्स को अलग-अलग इंटरफेस के माध्यम से उजागर करना)।
If you make class Foo refer directly to class BarImpl, you're strongly committing yourself to change Foo every time you change BarImpl
को बदलने पर, फू में किन बदलावों से बचा जा सकता है interface Bar
? जब तक एक विधि के हस्ताक्षर और कार्यक्षमता BarImpl में नहीं बदलती, तब तक Foo को इंटरफ़ेस (इंटरफ़ेस का पूरा उद्देश्य) के बिना भी बदलाव की आवश्यकता नहीं होगी। मैं उस परिदृश्य के बारे में बात कर रहा हूँ जहाँ केवल एक वर्ग यानी BarImpl
बार को लागू करता है। मल्टी क्लास परिदृश्य के लिए, मैं डिपेंडेंसी इनवर्जन प्रिंसिपल को समझता हूं और यह कैसे इंटरफ़ेस सहायक है।
किसी व्यवहार को परिभाषित करने के लिए इंटरफेस को नामित किया गया है, अर्थात फ़ंक्शन / विधियों के प्रोटोटाइप का एक सेट। इंटरफ़ेस को लागू करने वाले प्रकार उस व्यवहार को लागू करेंगे, इसलिए जब आप इस प्रकार के साथ व्यवहार करते हैं तो आप जानते हैं (आंशिक रूप से) कि यह कैसा व्यवहार है।
एक इंटरफ़ेस को परिभाषित करने की आवश्यकता नहीं है यदि आप जानते हैं कि इसके द्वारा परिभाषित व्यवहार केवल एक बार उपयोग किया जाएगा। KISS (यह आसान बेवकूफ रखने के लिए,)
जबकि सिद्धांत में आपके पास इंटरफ़ेस के खातिर सिर्फ एक इंटरफेस नहीं होना चाहिए, यानिस रिज़ोस का जवाब आगे के संकेत के साथ है:
जब आप इकाई परीक्षण लिख रहे हैं और Moq या FakeItEasy जैसे नकली फ्रेमवर्क का उपयोग कर रहे हैं (मेरे द्वारा उपयोग किए गए दो सबसे हाल के नाम), तो आप स्पष्ट रूप से एक और वर्ग बना रहे हैं जो इंटरफ़ेस को लागू करता है। कोड या स्थैतिक विश्लेषण की खोज का दावा हो सकता है कि सिर्फ एक कार्यान्वयन है, लेकिन वास्तव में आंतरिक नकली कार्यान्वयन है। जब भी आप मॉक लिखना शुरू करते हैं, आप पाएंगे कि इंटरफेस निकालने से समझ में आता है।
लेकिन रुकिए, और भी है। अधिक परिदृश्य हैं जहां निहित इंटरफ़ेस कार्यान्वयन हैं। उदाहरण के लिए .NET के WCF संचार स्टैक का उपयोग करना, एक दूरस्थ सेवा के लिए एक प्रॉक्सी बनाता है, जो फिर से, इंटरफ़ेस को लागू करता है।
एक स्वच्छ कोड वातावरण में, मैं यहां बाकी जवाबों से सहमत हूं। हालाँकि, किसी भी चौखटे, पैटर्न या निर्भरता पर ध्यान दें जो आपके लिए इंटरफेस का उपयोग कर सकती है।
नहीं, आपको उनकी आवश्यकता नहीं है, और मैं इसे हर वर्ग के संदर्भ के लिए स्वचालित रूप से इंटरफेस बनाने के लिए एक विरोधी पैटर्न मानता हूं।
सब कुछ के लिए फू / FooImpl बनाने के लिए एक वास्तविक लागत है। IDE मुक्त करने के लिए इंटरफ़ेस / कार्यान्वयन बना सकता है, लेकिन जब आप कोड नेविगेट कर रहे हों, तो आपके पास foo.doSomething()
इंटरफ़ेस हस्ताक्षर लेने के लिए F3 / F12 से अतिरिक्त संज्ञानात्मक भार है, न कि वास्तविक कार्यान्वयन जिसे आप चाहते हैं। साथ ही आपके पास हर चीज के लिए एक के बजाय दो फाइलों का समूह है।
इसलिए आपको इसे तभी करना चाहिए जब आपको वास्तव में किसी चीज की जरूरत हो।
अब प्रतिवादों को संबोधित करते हुए:
मुझे डिपेंडेंसी इंजेक्शन फ्रेमवर्क के लिए इंटरफेस चाहिए
चौखटे का समर्थन करने के लिए इंटरफेस विरासत हैं। जावा में, डायनेमिक प्रॉक्सी, पूर्व-सीजीएलआईबी के लिए इंटरफेस की आवश्यकता होती थी। आज, आपको आमतौर पर इसकी आवश्यकता नहीं है। यह प्रगति और डेवलपर उत्पादकता के लिए एक वरदान माना जाता है कि आपको ईजेबी 3, स्प्रिंग आदि में अब उनकी आवश्यकता नहीं है।
मुझे यूनिट टेस्टिंग के लिए मोक्स चाहिए
यदि आप अपने स्वयं के मोज़ेक लिखते हैं और दो वास्तविक कार्यान्वयन हैं, तो एक इंटरफ़ेस उपयुक्त है। अगर आपके कोडबेस में FooImpl और TestFoo दोनों हों, तो शायद हम पहली बार में यह चर्चा नहीं करेंगे।
लेकिन अगर आप Moq, EasyMock, या Mockito जैसे मॉकिंग फ्रेमवर्क का उपयोग कर रहे हैं, तो आप कक्षाएं मॉक कर सकते हैं और आप इंटरफेस नहीं बनाते हैं। यह foo.method = mockImplementation
एक गतिशील भाषा में स्थापित करने के लिए अनुरूप है जहां तरीकों को सौंपा जा सकता है।
हमें डिपेंडेंसी इनवर्जन सिद्धांत (DIP) का पालन करने के लिए इंटरफेस की आवश्यकता है
डीआईपी का कहना है कि आप अनुबंधों (इंटरफेस) पर निर्भर हैं और कार्यान्वयन नहीं। लेकिन एक वर्ग पहले से ही एक अनुबंध और एक अमूर्त है। यह सार्वजनिक / निजी कीवर्ड के लिए है। विश्वविद्यालय में, विहित उदाहरण एक मैट्रिक्स या बहुपद वर्ग की तरह था - उपभोक्ताओं के पास मैट्रिक्स बनाने, उन्हें जोड़ने आदि के लिए एक सार्वजनिक एपीआई है, लेकिन मैट्रिक्स को विरल या घने रूप में कार्यान्वित करने की अनुमति नहीं है। उस बिंदु को सिद्ध करने के लिए कोई IMatrix या MatrixImpl आवश्यक नहीं था।
इसके अलावा, डीआईपी को अक्सर हर वर्ग / विधि कॉल स्तर पर लागू किया जाता है, न केवल प्रमुख मॉड्यूल सीमाओं पर। एक संकेत जो आप डीआईपी लागू कर रहे हैं, वह यह है कि आपका इंटरफ़ेस और कार्यान्वयन लॉक-स्टेप में ऐसे बदलता है कि आपको एक के बजाय एक परिवर्तन करने के लिए दो फ़ाइलों को स्पर्श करना होगा। यदि DIP को उचित रूप से लागू किया जाता है, तो इसका मतलब है कि आपके इंटरफ़ेस को अक्सर बदलना नहीं चाहिए। इसके अलावा, एक और संकेत यह है कि आपके इंटरफ़ेस में केवल एक वास्तविक उपभोक्ता (अपना स्वयं का अनुप्रयोग) है। यदि आप कई अलग-अलग ऐप्स में उपभोग के लिए एक क्लास लाइब्रेरी का निर्माण कर रहे हैं तो अलग कहानी।
यह अंकल बॉब मार्टिन के मॉकिंग के बारे में एक कोरोलरी है - आपको केवल प्रमुख वास्तुशिल्प सीमाओं पर मज़ाक करना चाहिए। एक वेबपेज में HTTP और DB एक्सेस प्रमुख सीमाएँ हैं। बीच में सभी वर्ग / विधि कॉल नहीं हैं। वही डीआईपी के लिए जाता है।
यह सभी देखें:
new Mockup<YourClass>() {}
और इसके कंस्ट्रक्टरों सहित पूरे वर्ग का मज़ाक उड़ाया जाता है, चाहे वह एक इंटरफ़ेस, अमूर्त वर्ग या कंक्रीट क्लास हो। यदि आप ऐसा करना चाहते हैं तो आप कंस्ट्रक्टर के व्यवहार को "ओवरराइड" भी कर सकते हैं। मुझे लगता है कि मॉकिटो या पॉवर्मॉक में समान तरीके हैं।
ऐसा लगता है कि बाड़ के दोनों किनारों पर दिए गए उत्तर इस में सम्मिलित किए जा सकते हैं:
अच्छी तरह से डिजाइन करें, और जहां इंटरफेस की आवश्यकता होती है, वहां इंटरफेस लगाएं।
जैसा कि मैंने यानी के जवाब में अपनी प्रतिक्रिया में उल्लेख किया है , मुझे नहीं लगता कि आप कभी भी इंटरफेस के बारे में एक कठिन और तेज़ नियम बना सकते हैं। नियम को परिभाषा के अनुसार, लचीला होना चाहिए। इंटरफेस पर मेरा नियम है कि एक इंटरफ़ेस का उपयोग किया जाना चाहिए कहीं भी आप एक एपीआई बना रहे हैं। और एक एपीआई बनाया जाना चाहिए कहीं भी आप जिम्मेदारी के एक डोमेन से दूसरे में सीमा पार कर रहे हैं।
उदाहरण के लिए (बुरी तरह से वंचित) उदाहरण के लिए, मान लें कि आप एक Car
वर्ग बना रहे हैं । आपकी कक्षा में, आपको निश्चित रूप से UI परत की आवश्यकता होगी। इस विशिष्ट उदाहरण में, यह एक का रूप ले लेता IginitionSwitch
, SteeringWheel
, GearShift
, GasPedal
, और BrakePedal
। चूंकि इस कार में AutomaticTransmission
ए है, इसलिए आपको इसकी आवश्यकता नहीं है ClutchPedal
। (और चूंकि यह एक भयानक कार है, कोई ए / सी, रेडियो या सीट नहीं है। वास्तव में, फ़्लोरबोर्ड भी गायब हैं - आपको बस उस स्टीयरिंग व्हील पर लटकना होगा और सर्वश्रेष्ठ की उम्मीद करनी होगी!)
तो इनमें से किस वर्ग को एक इंटरफ़ेस की आवश्यकता है? जवाब उन सभी में से हो सकता है, या उनमें से कोई भी - आपके डिजाइन पर निर्भर करता है।
आपके पास एक इंटरफ़ेस हो सकता है जो इस तरह दिखे:
Interface ICabin
Event IgnitionSwitchTurnedOn()
Event IgnitionSwitchTurnedOff()
Event BrakePedalPositionChanged(int percent)
Event GasPedalPositionChanged(int percent)
Event GearShiftGearChanged(int gearNum)
Event SteeringWheelTurned(float degree)
End Interface
उस समय, उन वर्गों का व्यवहार ICabin Interface / API का हिस्सा बन जाता है। इस उदाहरण में कक्षाएं (यदि कुछ हैं) संभवतः कुछ गुणों और एक फ़ंक्शन या दो के साथ सरल हैं। और जो आप अपने डिजाइन के साथ स्पष्ट रूप से कह रहे हैं, वह यह है कि ये वर्ग पूरी तरह से मौजूद हैं जो कि आपके पास आईसीबिन के किसी भी ठोस कार्यान्वयन का समर्थन करने के लिए हैं, और वे अपने दम पर मौजूद नहीं हो सकते हैं, या वे आईसीबिन संदर्भ के बाहर अर्थहीन हैं।
यह वही कारण है कि आप निजी सदस्यों को इकाई-परीक्षण नहीं करते हैं - वे केवल सार्वजनिक एपीआई का समर्थन करने के लिए मौजूद हैं , और इस प्रकार उनके व्यवहार को एपीआई का परीक्षण करके परीक्षण किया जाना चाहिए।
इसलिए यदि आपकी कक्षा पूरी तरह से किसी अन्य वर्ग का समर्थन करने के लिए मौजूद है, और वैचारिक रूप से आप इसे देखते हैं कि वास्तव में यह स्वयं का डोमेन नहीं है तो इंटरफ़ेस को छोड़ना ठीक है। लेकिन अगर आपकी कक्षा इतनी महत्वपूर्ण है कि आप इसे बड़े होने पर विचार करें कि यह स्वयं का डोमेन है, तो आगे बढ़ें और इसे एक इंटरफ़ेस दें।
संपादित करें:
बार-बार (इस उत्तर सहित) आप 'डोमेन', 'निर्भरता' (अक्सर 'इंजेक्शन' के साथ युग्मित) जैसी चीजों को पढ़ेंगे, जो कि आपके लिए एक ऐसी चीज का मतलब नहीं है जब आप कार्यक्रम शुरू कर रहे हैं (उन्हें यकीन है कि नहीं किया था मेरे लिए कुछ भी मतलब है)। डोमेन के लिए, इसका मतलब है कि यह कैसा लगता है:
वह क्षेत्र जिस पर प्रभुत्व या अधिकार छेड़ा हुआ है; एक संप्रभु या सामान्य राष्ट्र या इस तरह की संपत्ति। इसके अलावा आलंकारिक रूप से उपयोग किया जाता है। [वर्डनेट सेंस 2] [१ ९ १३ वेबस्टर]
मेरे उदाहरण के संदर्भ में - आइए विचार करें IgnitionSwitch
। मीटस्पेस कार में, इग्निशन स्विच के लिए जिम्मेदार है:
उन गुणों के डोमेन को IgnitionSwitch
या दूसरे शब्दों में, इसके बारे में क्या पता है और इसके लिए जिम्मेदार है।
IgnitionSwitch
लिए ज़िम्मेदार नहीं है GasPedal
। इग्निशन स्विच पूरी तरह से गैस पेडल से अनभिज्ञ है। वे दोनों एक दूसरे से पूरी तरह से स्वतंत्र हैं (हालांकि दोनों के बिना एक कार काफी बेकार होगी!)।
जैसा कि मैंने मूल रूप से कहा है, यह आपके डिजाइन पर निर्भर करता है। आप डिजाइन कर सकते हैं IgnitionSwitch
जिसमें दो मान थे: ऑन ( True
) और ऑफ ( False
)। या आप इसे इसके लिए प्रदान की गई कुंजी, और अन्य कार्यों के होस्ट को प्रमाणित करने के लिए डिज़ाइन कर सकते हैं। एक डेवलपर होने का कठिन हिस्सा यह तय कर रहा है कि रेत में लाइनों को कैसे खींचना है - और ईमानदारी से अधिकांश समय यह पूरी तरह से सापेक्ष है। रेत में वे रेखाएँ महत्वपूर्ण हैं, हालांकि - यही वह जगह है जहाँ आपका एपीआई है, और इस प्रकार जहाँ आपका इंटरफेस होना चाहिए।
से MSDN :
इंटरफेस उन स्थितियों के लिए बेहतर अनुकूल हैं जिनमें आपके अनुप्रयोगों को कुछ कार्यक्षमता प्रदान करने के लिए कई संभावित असंबंधित वस्तु प्रकारों की आवश्यकता होती है।
आधार कक्षाओं की तुलना में इंटरफेस अधिक लचीले होते हैं क्योंकि आप एकल कार्यान्वयन को परिभाषित कर सकते हैं जो कई इंटरफेस को लागू कर सकता है।
इंटरफेस उन स्थितियों में बेहतर होते हैं जिनमें आपको आधार वर्ग से कार्यान्वयन की आवश्यकता नहीं होती है।
इंटरफेस उन मामलों में उपयोगी होते हैं जहां आप क्लास इनहेरिटेंस का उपयोग नहीं कर सकते हैं। उदाहरण के लिए, संरचनाएं कक्षाओं से विरासत में नहीं मिल सकती हैं, लेकिन वे इंटरफेस को लागू कर सकते हैं।
आम तौर पर एक एकल वर्ग के मामले में, एक इंटरफ़ेस को लागू करना आवश्यक नहीं होगा, लेकिन आपकी परियोजना के भविष्य को देखते हुए, यह कक्षाओं के आवश्यक व्यवहार को औपचारिक रूप से परिभाषित करने के लिए उपयोगी हो सकता है।
प्रश्न का उत्तर देने के लिए: इसके अलावा भी बहुत कुछ है।
एक इंटरफ़ेस का एक महत्वपूर्ण पहलू इरादे है।
एक इंटरफ़ेस "एक अमूर्त प्रकार है जिसमें कोई डेटा नहीं होता है, लेकिन व्यवहारों को उजागर करता है" - इंटरफ़ेस (कंप्यूटिंग) इसलिए यदि यह एक व्यवहार है, या व्यवहार का एक सेट है, जो वर्ग का समर्थन करता है, तो इंटरफ़ेस की तुलना में सही पैटर्न की संभावना है। यदि, हालांकि, व्यवहार (एस) वर्ग द्वारा सन्निहित अवधारणा के लिए आंतरिक हैं (हैं), तो आप संभवतः एक इंटरफ़ेस नहीं चाहते हैं।
पूछने का पहला सवाल यह है कि उस चीज़ या प्रक्रिया की प्रकृति क्या है जिसे आप प्रतिनिधित्व करने की कोशिश कर रहे हैं। फिर उस प्रकृति को एक निश्चित तरीके से लागू करने के व्यावहारिक कारणों का पालन करें।
चूंकि आपने यह प्रश्न पूछा है, इसलिए मुझे लगता है कि आपने पहले से ही कई कार्यान्वयनों को छिपाने वाले इंटरफ़ेस के हितों को देखा है। यह निर्भरता उलटा सिद्धांत द्वारा प्रकट किया जा सकता है।
हालाँकि, इंटरफ़ेस की आवश्यकता या उसके कार्यान्वयन की संख्या पर निर्भर नहीं करता है। एक इंटरफ़ेस की वास्तविक भूमिका यह है कि यह एक अनुबंध को परिभाषित करता है कि यह कैसे लागू किया जाना चाहिए इसके बजाय क्या सेवा प्रदान की जानी चाहिए।
एक बार अनुबंध परिभाषित होने के बाद, दो या अधिक टीमें स्वतंत्र रूप से काम कर सकती हैं। मान लें कि आप एक मॉड्यूल ए पर काम कर रहे हैं और यह मॉड्यूल बी पर निर्भर करता है, बी पर एक इंटरफ़ेस बनाने का तथ्य बी के कार्यान्वयन के बारे में चिंता किए बिना अपने काम को जारी रखने की अनुमति देता है क्योंकि सभी विवरण इंटरफ़ेस द्वारा छिपे हुए हैं। इस प्रकार, वितरित प्रोग्रामिंग संभव हो जाती है।
भले ही मॉड्यूल बी के पास इसके इंटरफ़ेस का केवल एक कार्यान्वयन है, इंटरफ़ेस अभी भी आवश्यक है।
अंत में, एक इंटरफ़ेस अपने उपयोगकर्ताओं से कार्यान्वयन विवरण छिपाता है। इंटरफ़ेस पर प्रोग्रामिंग करने से अधिक दस्तावेज़ लिखने में मदद मिलती है क्योंकि अनुबंध को परिभाषित किया जाना चाहिए, अधिक मॉड्यूलर सॉफ्टवेयर लिखने के लिए, यूनिट परीक्षणों को बढ़ावा देने और विकास की गति को तेज करने के लिए।
यहां सभी उत्तर बहुत अच्छे हैं। वास्तव में अधिकांश समय आपको एक अलग इंटरफ़ेस लागू करने की आवश्यकता नहीं होती है। लेकिन ऐसे मामले हैं जहां आप इसे वैसे भी करना चाह सकते हैं। यहाँ कुछ मामला है जहाँ मैं यह करता हूँ:
क्लास एक अन्य इंटरफ़ेस को लागू करता है जिसे मैं
एडाप्टर क्लास के साथ हैप्पन को अक्सर उजागर नहीं करना चाहता हूं जो कि थर्ड पार्टी कोड को ब्रिज करता है।
interface NameChangeListener { // Implemented by a lot of people
void nameChanged(String name);
}
interface NameChangeCount { // Only implemented by my class
int getCount();
}
class NameChangeCounter implements NameChangeListener, NameChangeCount {
...
}
class SomeUserInterface {
private NameChangeCount currentCount; // Will never know that you can change the counter
}
वर्ग एक विशिष्ट तकनीक का उपयोग करता है जो
बाहरी पुस्तकालयों के साथ बातचीत करते समय अधिकतर गर्त को लीक नहीं करना चाहिए । यहां तक कि अगर केवल एक कार्यान्वयन है, तो मैं यह सुनिश्चित करने के लिए एक इंटरफ़ेस का उपयोग करता हूं कि मैं बाहरी पुस्तकालय के साथ अनावश्यक युग्मन का परिचय नहीं देता हूं।
interface SomeRepository { // Guarantee that the external library details won't leak trough
...
}
class OracleSomeRepository implements SomeRepository {
... // Oracle prefix allow us to quickly know what is going on in this class
}
क्रॉस लेयर कम्युनिकेशन
भले ही केवल एक यूआई वर्ग कभी भी डोमेन वर्ग में से एक को लागू करता है, यह उन परत के बीच बेहतर पृथक्करण की अनुमति देता है और सबसे महत्वपूर्ण बात यह चक्रीय निर्भरता से बचता है।
package project.domain;
interface UserRequestSource {
public UserRequest getLastRequest();
}
class UserBehaviorAnalyser {
private UserRequestSource requestSource;
}
package project.ui;
class OrderCompleteDialog extends SomeUIClass implements project.domain.UserRequestSource {
// UI concern, no need for my domain object to know about this method.
public void displayLabelInErrorMode();
// They most certainly need to know about *that* though
public UserRequest getLastRequest();
}
केवल विधि का सबसेट सबसे अधिक वस्तु के लिए उपलब्ध होना चाहिए
ज्यादातर तब होता है जब मेरे पास ठोस वर्ग पर कुछ कॉन्फ़िगरेशन विधि होती है
interface Sender {
void sendMessage(Message message)
}
class PacketSender implements Sender {
void sendMessage(Message message);
void setPacketSize(int sizeInByte);
}
class Throttler { // This class need to have full access to the object
private PacketSender sender;
public useLowNetworkUsageMode() {
sender.setPacketSize(LOW_PACKET_SIZE);
sender.sendMessage(new NotifyLowNetworkUsageMessage());
... // Other details
}
}
class MailOrder { // Not this one though
private Sender sender;
}
इसलिए अंत में मैं इंटरफ़ेस का उपयोग उसी कारण से करता हूं जो मैं निजी क्षेत्र का उपयोग करता हूं: अन्य ऑब्जेक्ट में सामान तक पहुंच नहीं होनी चाहिए जो उन्हें एक्सेस नहीं करना चाहिए। अगर मेरे पास ऐसा कोई मामला है, तो मैं एक इंटरफ़ेस लागू करता हूं, भले ही केवल एक वर्ग इसे लागू करे।
इंटरफेस वास्तव में महत्वपूर्ण हैं लेकिन आपके पास उनकी संख्या को नियंत्रित करने का प्रयास करें।
बस के बारे में सब कुछ के लिए इंटरफेस बनाने की सड़क नीचे चला गया है यह 'कटा हुआ स्पेगेटी' कोड के साथ समाप्त करने के लिए आसान है। मैं आयेंद रहियन की अधिक बुद्धिमत्ता का सम्मान करता हूँ जिन्होंने इस विषय पर कुछ बहुत ही बुद्धिमानी भरे शब्द पोस्ट किए हैं:
http://ayende.com/blog/153889/limit-your-abstractions-analyzing-a-ddd-application
यह एक पूरी श्रृंखला की उनकी पहली पोस्ट है इसलिए पढ़ते रहें!
एक कारण जो आप अभी भी इस मामले में एक इंटरफ़ेस शुरू करना चाहते हैं, वह है डिपेंडेंसी इनवर्जन सिद्धांत का पालन करना । यही है, जो मॉड्यूल वर्ग का उपयोग करता है वह एक ठोस कार्यान्वयन के आधार पर इसके (यानी इंटरफ़ेस) के एक अमूर्त पर निर्भर करेगा। यह निम्न स्तर के घटकों से उच्च-स्तरीय घटकों को डिकॉय करता है।
कुछ भी करने का कोई वास्तविक कारण नहीं है। इंटरफेस आपकी मदद करने के लिए हैं न कि आउटपुट प्रोग्राम के लिए। इसलिए, भले ही इंटरफ़ेस एक लाख वर्गों द्वारा लागू किया गया हो, कोई नियम नहीं है जो कहता है कि आपको एक बनाना होगा। आप एक बनाते हैं ताकि जब आप, या कोई और जो आपके कोड का उपयोग करता है, तो वह सभी कार्यान्वयनों के लिए इसे बदल देना चाहता है। एक इंटरफ़ेस बनाना आपको भविष्य के सभी मामलों में सहयोगी करेगा जहाँ आप एक और वर्ग बनाना चाहते हैं जो इसे लागू करता है।
हमेशा एक वर्ग के लिए एक इंटरफ़ेस को परिभाषित करने की आवश्यकता नहीं होती है।
मूल्य वस्तुओं की तरह सरल वस्तुओं में कई कार्यान्वयन नहीं होते हैं। उन्हें या तो मज़ाक करने की ज़रूरत नहीं है। कार्यान्वयन का परीक्षण स्वयं किया जा सकता है और जब अन्य वर्गों का परीक्षण किया जाता है जो उन पर निर्भर करते हैं, तो वास्तविक मूल्य वस्तु का उपयोग किया जा सकता है।
याद रखें कि इंटरफ़ेस बनाने में एक लागत है। इसे कार्यान्वयन के साथ अद्यतन करने की आवश्यकता है, इसे एक अतिरिक्त फ़ाइल की आवश्यकता है, और कुछ आईडीई को कार्यान्वयन में ज़ूम करने में परेशानी होगी, इंटरफ़ेस नहीं।
इसलिए मैं केवल उच्च स्तर की कक्षाओं के लिए इंटरफेस को परिभाषित करता हूं, जहां आप कार्यान्वयन से एक अमूर्त चाहते हैं।
ध्यान दें कि एक वर्ग के साथ आपको मुफ्त में एक इंटरफ़ेस मिलता है। कार्यान्वयन के अलावा, एक वर्ग सार्वजनिक तरीकों के सेट से एक इंटरफ़ेस को परिभाषित करता है। वह इंटरफ़ेस सभी व्युत्पन्न वर्गों द्वारा कार्यान्वित किया जाता है। यह कड़ाई से एक इंटरफ़ेस नहीं बोल रहा है, लेकिन इसका उपयोग उसी तरह से किया जा सकता है। इसलिए मुझे नहीं लगता कि क्लास के नाम के तहत पहले से मौजूद इंटरफेस को फिर से बनाना जरूरी है।