निम्न दो कारणों से OOP में निर्भरता प्रबंधन एक बड़ी समस्या है:
- डेटा और कोड के तंग युग्मन।
- साइड इफेक्ट्स का सर्वव्यापी उपयोग।
अधिकांश OO प्रोग्रामर डेटा और कोड के तंग युग्मन को पूरी तरह से फायदेमंद मानते हैं, लेकिन यह एक लागत के साथ आता है। परतों के माध्यम से डेटा के प्रवाह को प्रबंधित करना किसी भी प्रतिमान में प्रोग्रामिंग का एक अपरिहार्य हिस्सा है। अपने डेटा और कोड को युग्मित करने से अतिरिक्त समस्या आती है कि यदि आप एक निश्चित बिंदु पर फ़ंक्शन का उपयोग करना चाहते हैं , तो आपको उस बिंदु पर अपनी वस्तु प्राप्त करने का एक तरीका खोजना होगा।
साइड इफेक्ट्स का उपयोग समान कठिनाइयों का निर्माण करता है। यदि आप कुछ कार्यक्षमता के लिए एक साइड इफेक्ट का उपयोग करते हैं, लेकिन इसके कार्यान्वयन को स्वैप करने में सक्षम होना चाहते हैं, तो आपके पास उस निर्भरता को इंजेक्ट करने के अलावा और कोई विकल्प नहीं है।
एक उदाहरण के रूप में एक स्पैमर प्रोग्राम पर विचार करें जो ईमेल पतों के लिए वेब पेजों को स्क्रैप करता है और फिर उन्हें ईमेल करता है। यदि आपके पास DI मानसिकता है, तो अभी आप उन सेवाओं के बारे में सोच रहे हैं जिन्हें आप इंटरफेस के पीछे संलग्न करेंगे, और कौन सी सेवाओं को इंजेक्ट किया जाएगा। मैं उस डिज़ाइन को पाठक के लिए एक अभ्यास के रूप में छोड़ दूँगा। यदि आपके पास एक एफपी मानसिकता है, तो अभी आप कार्यों की सबसे निचली परत के लिए इनपुट और आउटपुट के बारे में सोच रहे हैं, जैसे:
- एक वेब पेज एड्रेस इनपुट करें, उस पेज के टेक्स्ट को आउटपुट करें।
- किसी पृष्ठ के पाठ को इनपुट करें, उस पृष्ठ के लिंक की सूची तैयार करें।
- किसी पृष्ठ के पाठ को इनपुट करें, उस पृष्ठ पर ईमेल पतों की एक सूची तैयार करें।
- ईमेल पतों की एक सूची इनपुट करें, डुप्लिकेट हटाए गए ईमेल पतों की एक सूची आउटपुट करें।
- एक ईमेल पता इनपुट करें, उस पते के लिए एक स्पैम ईमेल आउटपुट करें।
- एक स्पैम ईमेल इनपुट करें, उस ईमेल को भेजने के लिए एसएमटीपी कमांड को आउटपुट करें।
जब आप इनपुट और आउटपुट के संदर्भ में सोचते हैं, तो कोई फ़ंक्शन निर्भरता नहीं होती है, केवल डेटा निर्भरता होती है। यही कारण है कि उन्हें इकाई परीक्षण के लिए इतना आसान बनाता है। आपकी अगली लेयर अप एक फ़ंक्शन के आउटपुट के लिए अगले इनपुट में दिए जाने की व्यवस्था करती है, और आवश्यकतानुसार विभिन्न कार्यान्वयन को आसानी से स्वैप कर सकती है।
एक बहुत ही वास्तविक अर्थ में, कार्यात्मक प्रोग्रामिंग स्वाभाविक रूप से आपको अपने फ़ंक्शन निर्भरताओं को हमेशा उल्टा करने के लिए जोड़ता है, और इसलिए आमतौर पर आपको इस तथ्य के बाद ऐसा करने के लिए कोई विशेष उपाय करने की आवश्यकता नहीं होती है। जब आप करते हैं, तो उच्च-क्रम वाले फ़ंक्शन, क्लोजर और आंशिक अनुप्रयोग जैसे उपकरण कम बॉयलरप्लेट के साथ पूरा करना आसान बनाते हैं।
ध्यान दें कि यह स्वयं निर्भरताएँ नहीं हैं जो समस्याग्रस्त हैं। यह निर्भरताएं हैं जो गलत तरीके से इंगित करती हैं। अगली परत की तरह एक समारोह हो सकता है:
processText = spamToSMTP . emailAddressToSpam . removeEmailDups . textToEmailAddresses
इस परत के लिए पूरी तरह से ठीक है कि इस तरह निर्भरताएं कठोर-कोडित होती हैं, क्योंकि इसका एकमात्र उद्देश्य निचली परत के कार्यों को एक साथ गोंद करना है। कार्यान्वयन को स्वैप करना एक अलग संरचना बनाने के समान सरल है:
processTextFancy = spamToSMTP . emailAddressToFancySpam . removeEmailDups . textToEmailAddresses
साइड इफेक्ट्स की कमी से यह आसान पुनर्मूल्यांकन संभव है। निचली परत के कार्य एक दूसरे से पूरी तरह से स्वतंत्र हैं। अगली परत ऊपर चुन सकती है जो processText
वास्तव में कुछ उपयोगकर्ता विन्यास के आधार पर उपयोग की जाती है:
actuallyUsedProcessText = if (config == "Fancy") then processTextFancy else processText
फिर से, एक मुद्दा नहीं है क्योंकि सभी निर्भरताएं एक तरह से इंगित करती हैं। हम सभी को उसी तरह इंगित करने के लिए कुछ निर्भरताओं को पलटने की आवश्यकता नहीं है, क्योंकि शुद्ध कार्यों ने हमें पहले से ही ऐसा करने के लिए मजबूर किया है।
ध्यान दें कि आप config
इसे शीर्ष पर जाँचने के बजाय सबसे निचली परत से गुज़रकर इसे और अधिक युग्मित बना सकते हैं । एफपी आपको ऐसा करने से नहीं रोकता है, लेकिन अगर आप कोशिश करते हैं तो यह बहुत अधिक कष्टप्रद है।