परिचय: आपके कोड को Dependency Injection की आवश्यकता क्यों है?
प्रत्येक JavaScript डेवलपर को देर-सबेर "टाइटली कपल्ड" (tightly coupled) कोड की समस्या का सामना करना पड़ता है। एक ऐसे UserService क्लास की कल्पना करें जो अपने अंदर Database और Logger का इंस्टेंस बनाता है। जब आप बिना वास्तविक डेटाबेस के UserService का परीक्षण करना चाहेंगे तो क्या होगा? या Logger को किसी दूसरे इम्प्लीमेंटेशन से बदलना चाहेंगे? सबसे अच्छी स्थिति में — आप पूरे क्लास को फिर से लिखेंगे, सबसे बुरी स्थिति में — आप पूरे एप्लिकेशन को तोड़ देंगे।
इस समस्या का समाधान है Dependency Injection (DI), या डिपेंडेंसी इंजेक्शन। यह डिज़ाइन के प्रमुख सिद्धांतों में से एक है जो Inversion of Control (IoC) की अवधारणा का आधार है। इस लेख में, हम समझेंगे कि DI क्या है, इसे फ्रेमवर्क के उपयोग के बिना शुद्ध JavaScript (Node.js) में कैसे लागू किया जाए, और स्केलेबल और टेस्ट करने योग्य एप्लिकेशन बनाने के लिए यह क्यों महत्वपूर्ण है।
सरल शब्दों में Dependency Injection क्या है?
कल्पना करें कि आप एक घर बना रहे हैं। दीवारों में हमेशा के लिए सॉकेट लगाने के बजाय, आप मानक कनेक्टर लगाते हैं। आज आप उनमें एक पुराना लैंप जोड़ते हैं, कल एक स्मार्ट लाइट। आप दीवारें नहीं बदलते — आप डिपेंडेंसी बदलते हैं।
प्रोग्रामिंग में Dependency Injection एक पैटर्न है जिसमें कोई ऑब्जेक्ट अपनी डिपेंडेंसी (अन्य ऑब्जेक्ट, सर्विस, कॉन्फ़िगरेशन) बाहर से प्राप्त करता है, न कि उन्हें स्वयं बनाता है। यह लिखने के बजाय:
// ❌ खराब: टाइट कपलिंगclass UserService { constructor() { this.db = new Database('mongodb://...'); this.logger = new ConsoleLogger(); }}हम यह लिखते हैं:
// ✅ अच्छा: डिपेंडेंसी इंजेक्शनclass UserService { constructor(database, logger) { this.db = database; this.logger = logger; }}अब UserService को यह नहीं पता कि Database और Logger कैसे बनाए जाते हैं। इसका काम केवल उनका उपयोग करना है। इसे ही इन्वर्ज़न ऑफ़ कंट्रोल कहते हैं: डिपेंडेंसी बनाने का नियंत्रण क्लास से कॉल करने वाले कोड में स्थानांतरित हो जाता है।
डिपेंडेंसी इंजेक्शन के प्रकार
इंजेक्शन के तीन मुख्य तरीके हैं:
- कंस्ट्रक्टर के माध्यम से (Constructor Injection) — सबसे सामान्य और पसंदीदा तरीका। ऑब्जेक्ट बनाते समय डिपेंडेंसी पास की जाती हैं।
- प्रॉपर्टी के माध्यम से (Property Injection) — ऑब्जेक्ट बनने के बाद डिपेंडेंसी सेट की जाती हैं। वैकल्पिक डिपेंडेंसी के लिए सुविधाजनक।
- मेथड के माध्यम से (Method Injection) — डिपेंडेंसी किसी विशिष्ट मेथड में पास की जाती है जब केवल एक क्रिया के लिए इसकी आवश्यकता होती है।
Node.js पर एक सरल DI-कंटेनर लिखना
बड़े प्रोजेक्ट्स में डिपेंडेंसी को मैन्युअल रूप से प्रबंधित करना कठिन हो जाता है। यहाँ DI-कंटेनर मदद करता है — एक ऑब्जेक्ट जो जानता है कि आपके एप्लिकेशन की सभी डिपेंडेंसी कैसे बनाई और संग्रहीत की जाएँ। आइए शुद्ध JavaScript में एक सरल लेकिन कार्यशील कंटेनर लिखें।
हमारा कंटेनर दो मोड सपोर्ट करेगा: singleton (पूरे एप्लिकेशन के लिए एक इंस्टेंस) और transient (हर अनुरोध पर नया इंस्टेंस)।
// di-container.jsclass DIContainer { constructor() { this.registry = new Map(); this.instances = new Map(); }
// फ़ैक्टरी फ़ंक्शन के साथ डिपेंडेंसी रजिस्टर करें register(name, factory, { singleton = true } = {}) { this.registry.set(name, { factory, singleton }); if (singleton) { this.instances.delete(name); // पुनः रजिस्टर करने पर कैश रीसेट करें } }
// डिपेंडेंसी का इंस्टेंस प्राप्त करें resolve(name) { const item = this.registry.get(name); if (!item) { throw new Error(`डिपेंडेंसी "${name}" नहीं मिली`); }