TypeScript में डिपेंडेंसी इंजेक्शन: सिद्धांत से व्यवहार तक
\n\nडिपेंडेंसी इंजेक्शन (DI) प्रमुख डिज़ाइन पैटर्न में से एक है जो लचीले, परीक्षण योग्य और रखरखाव योग्य एप्लिकेशन बनाने की अनुमति देता है। TypeScript में, सख्त टाइपिंग और डेकोरेटर की क्षमताओं के कारण, DI का कार्यान्वयन विशेष रूप से सुरुचिपूर्ण हो जाता है। इस लेख में, हम TypeScript का उपयोग करके व्यवहार में डिपेंडेंसी इंजेक्शन को लागू करने का तरीका समझेंगे, और देखेंगे कि यह पैटर्न आधुनिक विकास की आधारशिला क्यों है।
\n\nडिपेंडेंसी इंजेक्शन क्या है और इसकी आवश्यकता क्यों है?
\n\nडिपेंडेंसी इंजेक्शन (डिपेंडेंसी का बाहर से इंजेक्शन) एक पैटर्न है जिसमें ऑब्जेक्ट अपनी डिपेंडेंसी को बाहर से प्राप्त करता है, न कि उन्हें स्वयं बनाता है। क्लास के अंदर new SomeService() लिखने के बजाय, हम कंस्ट्रक्टर या मेथड के माध्यम से एक तैयार इंस्टेंस पास करते हैं।
DI के मुख्य लाभ:
\n- \n
- युग्मन में कमी (Coupling) — क्लासेस विशिष्ट कार्यान्वयन पर निर्भर नहीं होतीं, बल्कि केवल एब्स्ट्रैक्शन (इंटरफ़ेस) पर निर्भर होती हैं। \n
- परीक्षण का सरलीकरण — हम वास्तविक सेवाओं को आसानी से मॉक या स्टब से बदल सकते हैं। \n
- पुन: प्रयोज्यता में वृद्धि — उपभोक्ता कोड को बदले बिना डिपेंडेंसी को बदला जा सकता है। \n
- डिपेंडेंसी इनवर्जन सिद्धांत का पालन (SOLID से DIP) — उच्च-स्तरीय मॉड्यूल निम्न-स्तरीय मॉड्यूल पर निर्भर नहीं होते। \n
फ्रेमवर्क के बिना TypeScript में डिपेंडेंसी इंजेक्शन का कार्यान्वयन
\n\nचलिए एक सरल उदाहरण से शुरू करते हैं। मान लीजिए हमारे पास एक लॉगिंग सेवा और एक क्लास है जो इसका उपयोग करती है।
\n\n// DI के बिना - कठोर संबंध\nclass Logger {\n log(message: string): void {\n console.log(`[LOG]: ${message}`);\n }\n}\n\nclass UserService {\n private logger: Logger;\n\n constructor() {\n this.logger = new Logger(); // समस्या: कठोर निर्भरता\n }\n\n createUser(name: string): void {\n this.logger.log(`उपयोगकर्ता बनाया गया: ${name}`);\n // ... निर्माण का तर्क\n }\n}\n\n// DI के साथ - कंस्ट्रक्टर के माध्यम से\ninterface ILogger {\n log(message: string): void;\n}\n\nclass ConsoleLogger implements ILogger {\n log(message: string): void {\n console.log(`[CONSOLE LOG]: ${message}`);\n }\n}\n\nclass FileLogger implements ILogger {\n log(message: string): void {\n // फ़ाइल में लिखने का तर्क\n console.log(`[FILE LOG]: ${message}`);\n }\n}\n\nclass UserServiceWithDI {\n constructor(private logger: ILogger) {} // डिपेंडेंसी बाहर से इंजेक्ट की गई\n\n createUser(name: string): void {\n this.logger.log(`उपयोगकर्ता बनाया गया: ${name}`);\n }\n}\n\n// उपयोग\nconst consoleLogger = new ConsoleLogger();\nconst userService = new UserServiceWithDI(consoleLogger);\nuserService.createUser('Alice'); // [CONSOLE LOG]: उपयोगकर्ता बनाया गया: Alice\n\n\nजैसा कि आप देख सकते हैं, अब UserServiceWithDI को यह नहीं पता कि कौन सा लॉगर उपयोग किया जा रहा है। हम इसे आसानी से FileLogger या परीक्षण के लिए मॉक से बदल सकते हैं।
उन्नत DI: एक सरल IoC-कंटेनर बनाना
\n\nजब डिपेंडेंसी की संख्या अधिक हो जाती है, तो कंस्ट्रक्टर के माध्यम से मैन्युअल इंजेक्शन बोझिल हो जाता है। यहाँ IoC-कंटेनर (Inversion of Control Container) मदद करता है। यह ऑब्जेक्ट के निर्माण और जीवनचक्र का प्रबंधन करता है।
\n\nTypeScript में एक सरल कंटेनर लागू करते हैं:
\n\n// डिपेंडेंसी फैक्ट्री के लिए प्रकार\ntype Factory<T> = (container: Container) => T;\n\nclass Container {\n private factories = new Map<string, Factory<any>>();\n private instances = new Map<string, any>();\n\n // डिपेंडेंसी पंजीकरण (फैक्ट्री प्रत्येक अनुरोध पर कॉल की जाती है)\n register<T>(name: string, factory: Factory<T>): void {\n this.factories.set(name, factory);\n }\n\n // सिंगलटन पंजीकरण (फैक्ट्री एक बार कॉल की जाती है)\n singleton<T>(name: string, factory: Factory<T&g