क्या हम रणनीति पैटर्न और निर्भरता इंजेक्शन का उपयोग करके विरासत को पूरी तरह से बदल सकते हैं?


10

उदाहरण के लिए:

var duckBehaviors = new Duckbehavior();
duckBehaviors.quackBehavior = new Quack();
duckBehaviors.flyBehavior = new FlyWithWings();
Duck mallardDuck = new Duck(DuckTypes.MallardDuck, duckBehaviors)

चूंकि बत्तख वर्ग में सभी व्यवहार (सार) होते हैं, एक नया वर्ग MallardDuck(जो फैलता है Duck) बनाना आवश्यक नहीं लगता है।

संदर्भ: हेड फर्स्ट डिज़ाइन पैटर्न, अध्याय १।


Duckbehavior.quackBehaviorआपके कोड में और अन्य फ़ील्ड्स के प्रकार क्या हैं ?
15:

आपके उदाहरण में कोई निर्भरता इंजेक्शन नहीं है।
डेविड कॉनराड

11
वंशानुक्रम भयानक होता है जब आपका जूनियर मिड लेवल डेवलपर के लिए होता है क्योंकि इसमें चाल और चालन के पैटर्न का लंबा इतिहास होता है। लेकिन सबसे अनुभवी डेवलपर्स मैंने जब भी संभव हो रचना के आधार पर वास्तव में उथले विरासत पदानुक्रम पसंद करने के लिए बात की है। वंशानुक्रम आवश्यकता से अधिक तंग युग्मन पैदा कर सकता है और परिवर्तन को मुश्किल बना सकता है।
मार्क रोजर्स


5
@DavidConrad: ओपी वर्ग के भीतर नई-इंग नहीं कर रहा है । डि / आईओसी निर्भरता, इंजेक्शन लगाने के बारे में है नहीं कंटेनरों के बारे में या का उपयोग करते हुए कभी नहीं 'नई' के बारे में; यह एक पूरी तरह से रूढ़िवादी चिंता है। इसके अलावा, आपको हमेशा कहीं-न-कहीं कोड बदलना पड़ता है -यदि यह कंपोजीशन रूट या कुछ कॉन्फिग फाइल है। डक प्रकार के भीतर नियंत्रण यहां उल्टा है, क्योंकि निर्भरता के निर्माण को नियंत्रित करने वाली चीज डक कॉटर नहीं है, बल्कि कुछ बाहरी संदर्भ है; यह स्पष्टता के लिए दिया गया एक खिलौना उदाहरण है, यह पूरी तरह से ठीक है कि बाहरी संदर्भ को केवल कॉलिंग कोड द्वारा दर्शाया गया है।
फिलिप मिलोवानोविक

जवाबों:


21

ज़रूर, लेकिन हम उस रचना और प्रतिनिधिमंडल को बुलाते हैं । रणनीति पैटर्न और निर्भरता इंजेक्शन संरचनात्मक रूप से समान लग सकता है लेकिन उनके इरादे अलग हैं।

रणनीति पैटर्न एक ही इंटरफ़ेस के तहत व्यवहार के क्रम में संशोधन की अनुमति देता है। मैं एक मल्लार्ड बतख को उड़ने और पंखों को देखने के लिए उड़ने को कह सकता था। फिर इसे एक जेट पायलट बतख के लिए स्वैप करें और इसे डेल्टा एयरलाइंस के साथ उड़ते हुए देखें। यह करते हुए कि कार्यक्रम चल रहा है एक रणनीति पैटर्न बात है।

डिपेंडेंसी इंजेक्शन हार्ड कोडिंग निर्भरता से बचने की एक तकनीक है ताकि वे ग्राहकों को बदलने की आवश्यकता के बिना स्वतंत्र रूप से बदल सकें जब वे बदलते हैं। ग्राहक केवल यह जानने के बिना अपनी आवश्यकताओं को व्यक्त करते हैं कि वे कैसे मिलेंगे। इस प्रकार उनकी मुलाकात कैसे होती है इसका निर्णय कहीं और किया जाता है (आमतौर पर मुख्य रूप से)। इस तकनीक का उपयोग करने के लिए आपको दो बत्तखों की आवश्यकता नहीं है। बस कुछ ऐसा जो बतख को बिना जाने या परवाह किए इस्तेमाल करता है। कुछ ऐसा जो बतख का निर्माण नहीं करता है या उसकी तलाश नहीं करता है लेकिन जो भी बतख आपको सौंपता है उसका उपयोग करने के लिए पूरी तरह से खुश है।

अगर मेरे पास एक ठोस बतख वर्ग है तो मैं इसे लागू कर सकता हूं यह मक्खी व्यवहार है। मैं भी इसे एक राज्य चर के आधार पर फ्लाई-टू-विंग्स से फ्लाई-टू-डेल्टा के साथ व्यवहार स्विच कर सकता था। वह चर एक बूलियन, एक इंट हो सकता है, या यह एक FlyBehaviorऐसा flyतरीका हो सकता है जो एक ऐसी उड़ान शैली करता है जो मेरे बिना एक उड़ान शैली का परीक्षण करता है। अब मैं बतख के प्रकारों को बदले बिना उड़ान शैलियों को बदल सकता हूं। अब मॉलार्ड पायलट बन सकते हैं। यह रचना और प्रतिनिधिमंडल है । बतख एक फ्लाईबहेवियर से बना है और यह इसे करने के लिए उड़ान अनुरोध सौंप सकता है। आप एक ही बार में अपने सभी बत्तख व्यवहारों को बदल सकते हैं या प्रत्येक व्यवहार या बीच में किसी भी संयोजन के लिए कुछ रख सकते हैं।

इससे आपको वही सारी शक्तियाँ मिलती हैं जो विरासत में एक को छोड़कर होती हैं। वंशानुक्रम आपको अभिव्यक्त करता है कि आप बतख उपप्रकारों में कौन-सी विधियाँ ओवरराइड कर रहे हैं। रचना और प्रतिनिधिमंडल को प्रारंभ से उपप्रकारों को स्पष्ट रूप से सौंपने के लिए बत्तख की आवश्यकता होती है। यह कहीं अधिक लचीला है, लेकिन इसमें अधिक कीबोर्ड टाइपिंग शामिल है और बतख को यह जानना है कि यह क्या हो रहा है।

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

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

हालांकि बाद में चीजों को फाड़ने के लिए तैयार रहने से आप ओवर डिजाइनिंग से मुक्त हो सकते हैं, कुछ ऐसा डिजाइन करने में सक्षम होने के बारे में बहुत शक्तिशाली है जो बतख का उपयोग किए बिना यह पता करने के लिए करता है कि बतख वास्तव में क्या उपयोग करेगा। यह नहीं जानते कि शक्तिशाली सामान है। यह आपको थोड़ी देर के लिए बतख के बारे में सोचना बंद कर देता है और अपने बाकी कोड के बारे में सोचता है।

"क्या हम कर सकते हैं" और "हमें चाहिए" अलग-अलग प्रश्न हैं। पक्षपात पर अनुकूल रचना यह नहीं कहती है कि उत्तराधिकार का उपयोग कभी न करें। अभी भी ऐसे मामले हैं जहां विरासत सबसे अधिक समझ में आता है। मैं आपको अपना पसंदीदा उदाहरण दिखाऊंगा :

public class LoginFailure : System.ApplicationException {}

वंशानुक्रम आपको केवल एक पंक्ति में अधिक विशिष्ट, वर्णनात्मक नामों के साथ अपवाद बनाने देता है।

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


1
" एक अच्छे नाम के मूल्य को कभी कम मत समझो "। सम्राट के नए कपड़े समय: LoginExceptionएक अच्छा नाम नहीं है। यह क्लासिक "स्मर्फ नामकरण" है और, अगर मैं दूर ले जाता हूं, तो Exceptionमेरे पास सभी है Login, यह मुझे बताता है कि क्या गलत हुआ।
डेविड अरनो

अफसोस की बात है कि हम Exceptionहर अपवाद वर्ग के अंत में डालने के हास्यास्पद सम्मेलन के साथ फंस गए हैं , लेकिन कृपया "अच्छा" के साथ "इसके साथ अटक" भ्रमित न करें।
डेविड अरनो

@DavidArno यदि आप एक बेहतर नाम सुझा सकते हैं तो मैं सभी कान हूँ। यहां हमें मौजूदा कोड आधार के सम्मेलनों में नहीं फंसने का लाभ है। यदि आपके पास अपनी उंगलियों की एक तस्वीर के साथ दुनिया को बदलने की शक्ति है, तो आप इसे क्या नाम देंगे?
candied_orange

मैं उन्हें, नाम था StackOverflow, OutOfMemory, NullReferenceAccess, LoginFailureआदि मूल रूप से, "अपवाद" नाम से दूर ले। और, यदि आवश्यक हो, तो उन्हें ठीक करें ताकि यह बताए कि क्या गलत हुआ।
डेविड अरनो

@DavidArno आपकी आज्ञा से।
कैंडिड_ओरेंज

7

आप किसी भी अन्य कार्यप्रणाली के साथ लगभग किसी भी कार्यप्रणाली को बदल सकते हैं और फिर भी कार्यशील सॉफ़्टवेयर का उत्पादन कर सकते हैं। फिर भी कुछ दूसरों की तुलना में एक विशेष समस्या के लिए एक बेहतर फिट हैं।

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

जब आप अन्य लोगों की कृतियों के साथ अधिक अनुभवी और संघर्ष करते हैं, तो आप अंतिम चिंतन पर अधिक जोर देंगे।

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


-1

वंशानुक्रम उतना महत्वपूर्ण नहीं है जितना कभी सोचा गया था। यह अभी भी महत्वपूर्ण है , और इसे हटाना एक गलत गलती होगी।

एक चरम उदाहरण ऑब्जेक्टिव-सी है जहां सब कुछ NSObject का एक उपवर्ग है (संकलक वास्तव में आपको एक ऐसा वर्ग घोषित करने की अनुमति नहीं देता है जिसके पास बेसकलैस नहीं है, इसलिए जो कुछ भी संकलक में नहीं बनाया गया है उसे किसी चीज़ का उपवर्ग होना चाहिए संकलक में बनाया गया)। वहाँ NSObject में निर्मित उपयोगी सामान की एक बहुत कुछ है जिसे आपको याद नहीं करना होगा।

एक और दिलचस्प उदाहरण UIView है, जो iOS विकास के लिए UIKit में बुनियादी "दृश्य" वर्ग है। यह एक ऐसा वर्ग है जो एक तरह से थोड़ा सा अमूर्त वर्ग जैसा है जो कार्यक्षमता की घोषणा करता है कि उपवर्गों को भरना चाहिए, लेकिन यह अपने आप में उपयोगी भी है। इसमें UIKit द्वारा आपूर्ति किए गए उपवर्ग हैं, जिनका उपयोग अक्सर किया जाता है। डेवलपर द्वारा एक दृश्य में साक्षात्कार स्थापित करने से रचना होती है। और अक्सर डेवलपर-परिभाषित उपवर्ग होते हैं, जो अक्सर रचना का उपयोग करते हैं। कोई सख्त एकल नियम या यहां तक ​​कि नियम भी नहीं हैं, आप अपनी आवश्यकताओं के अनुसार जो भी उपयुक्त हो उपयोग करते हैं।


आपका "चरम उदाहरण" मोटे तौर पर सबसे आधुनिक ओओ भाषाएँ कैसे काम करता है: पायथन उपवर्ग type, जावा में हर गैर-आदिम से विरासत में मिला है Object, जावास्क्रिप्ट में सब कुछ एक प्रोटोटाइप के साथ समाप्त होता है Object, आदि
16

-1

[मैं टिट्युलर प्रश्न के एक चुटीले जवाब का खतरा होगा।]

क्या हम रणनीति पैटर्न और निर्भरता इंजेक्शन का उपयोग करके विरासत को पूरी तरह से बदल सकते हैं?

हां ... रणनीति पैटर्न को छोड़कर खुद विरासत का उपयोग करता है। इंटरफ़ेस पैटर्न पर रणनीति पैटर्न काम करता है। रचना + रणनीति के साथ वंशानुक्रम को बदलना वंशानुक्रम को किसी भिन्न स्थान पर ले जाता है। बहरहाल, ऐसा प्रतिस्थापन अक्सर करने योग्य होता है, क्योंकि यह पदानुक्रम को अलग करने की अनुमति देता है ।


2
" रणनीति पैटर्न इंटरफ़ेस विरासत पर काम करता है "। याद रखें, रणनीति पैटर्न एक डिजाइन पैटर्न है; कार्यान्वयन पैटर्न नहीं। तो यह इंटरफेस का उपयोग करके कार्यान्वित किया जा सकता है, लेकिन यह समान रूप से एक हैश / शब्दकोश फ़ंक्शन का उपयोग करके लागू किया जा सकता है।
डेविड अर्नो

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

प्लस एक, दोस्त: ... सामान्य शब्द "इंटरफ़ेस" के उचित उपयोग पर इंटरफ़ेस वंशानुक्रम , यश पर काम करता है। मुझे लगता है कि खराब या अक्षम वर्ग डिजाइन मूल कारण है जिससे यह सवाल उठता है। यह समझाने के लिए कि पुस्तक क्यों / कैसे लेगी; शैतान विवरण में है। मैंने डब्ल्यू / इनहेरिटेंस डिज़ाइनों पर काम किया है जो निहारने के लिए एक खुशी थी और एक ही समय में गहरी विरासत थी जो नरक थी। मैंने interfaceवंशानुक्रम डिजाइन को विरासत के साथ तय किया है। यहां छिपी समस्या असंगत कार्यान्वयन मॉर्फिंग निर्भर व्यवहार है। पी, एस। वंशानुक्रम और इंटरफ़ेस पारस्परिक रूप से अनन्य नहीं हैं,
रडार

@DavidArno टिप्पणी : ओपी प्रश्न से जुड़ी होने पर यह टिप्पणी ठीक होगी। ओपी प्रश्न तकनीकी रूप से गलत कहा गया है लेकिन हम अभी भी इसे प्राप्त करते हैं। मुद्दा यह कोई खास जवाब नहीं है।
रडारबॉब

@DeepakMishra टिप्पणी: । एक "इंटरफ़ेस" एक वर्ग के सभी सार्वजनिक सदस्य हैं। दुर्भाग्य से "इंटरफ़ेस" अर्थ अतिभारित है। हमें एक प्रोग्रामिंग भाषा के कीवर्ड के साथ सामान्य अर्थ को अलग करने के लिए सावधान रहना चाहिएinterface
रडार

-2

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

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

अब अगर कोड का पुन: उपयोग कुछ कार्यक्षमता के लिए समस्याग्रस्त हो जाता है, तो हम इसे रचनाकार के माध्यम से कार्यों में पारित कर सकते हैं।

फिर, यह वास्तव में आपके उपयोग के मामले पर निर्भर करता है। यदि आपके पास बस एक बतख और एक मॉलर्ड बतख है, तो एक श्रेणी पदानुक्रम एक बहुत सरल समाधान है।

लेकिन यहाँ एक उदाहरण है जहाँ आप रणनीति पैटर्न का उपयोग करना चाहते हैं: यदि आपके पास ग्राहक वर्ग हैं, और आप बिलिंग रणनीति (इंटरफ़ेस) में उत्तीर्ण होना चाहते हैं जो खुशहाल बिलिंग रणनीति या नियमित बिलिंग रणनीति हो सकती है, तो आप इसे पारित कर सकते हैं। कंस्ट्रक्टर में। इस तरह से आपको ग्राहकों के दो अलग-अलग वर्ग बनाने की ज़रूरत नहीं है और आपको पदानुक्रम की आवश्यकता नहीं है। आपके पास सिर्फ एक ग्राहक वर्ग है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.