मुझे पता है कि यह सूत्र इस बिंदु पर काफी पुराना है, लेकिन मुझे लगा कि मैं इस पर अपने विचारों के साथ झंकार करूंगा। टीएल; डीआर यह है कि जावास्क्रिप्ट के अप्रकाशित, गतिशील प्रकृति के कारण, आप वास्तव में निर्भरता इंजेक्शन (डीआई) पैटर्न का सहारा लेने या डीआई ढांचे का उपयोग किए बिना काफी कुछ कर सकते हैं। हालाँकि, जैसे-जैसे कोई एप्लिकेशन बड़ा और अधिक जटिल होता जाता है, DI निश्चित रूप से आपके कोड की स्थिरता बनाए रखने में मदद कर सकता है।
डि # C में
यह समझने के लिए कि DI को जावास्क्रिप्ट में कितनी बड़ी जरूरत नहीं है, यह C # जैसी जोरदार टाइप की गई भाषा को देखने में मददगार है। (उन लोगों से माफी जो सी # नहीं जानते हैं, लेकिन इसका पालन करना आसान होना चाहिए।) मान लीजिए कि हमारे पास एक ऐप है जो कार और उसके हॉर्न का वर्णन करता है। आप दो वर्गों को परिभाषित करेंगे:
class Horn
{
public void Honk()
{
Console.WriteLine("beep!");
}
}
class Car
{
private Horn horn;
public Car()
{
this.horn = new Horn();
}
public void HonkHorn()
{
this.horn.Honk();
}
}
class Program
{
static void Main()
{
var car = new Car();
car.HonkHorn();
}
}
इस तरह कोड लिखने के साथ कुछ समस्याएं हैं।
Car
वर्ग कसकर में सींग की विशेष कार्यान्वयन के लिए युग्मित हैHorn
वर्ग। अगर हम कार द्वारा उपयोग किए जाने वाले हॉर्न के प्रकार को बदलना चाहते हैं, तो हमें Car
क्लास को संशोधित करना होगा, भले ही हॉर्न का उपयोग न बदले। इससे परीक्षण करना भी मुश्किल हो जाता है क्योंकि हम Car
कक्षा को उसकी निर्भरता, वर्ग से अलग-थलग नहीं कर सकते Horn
।
-
Car
वर्ग के जीवन चक्र के लिए जिम्मेदार है Horn
वर्ग। इस तरह के एक साधारण उदाहरण में यह एक बड़ा मुद्दा नहीं है, लेकिन वास्तविक अनुप्रयोगों में निर्भरता में निर्भरताएं होंगी, जिनमें निर्भरताएं होंगी, आदि।Car
वर्ग को अपनी निर्भरता के पूरे पेड़ को बनाने के लिए जिम्मेदार होने की आवश्यकता होगी। यह न केवल जटिल और दोहराव वाला है, बल्कि यह वर्ग की "एकल जिम्मेदारी" का उल्लंघन करता है। यह एक कार होने पर ध्यान केंद्रित करना चाहिए, उदाहरण नहीं बनाना चाहिए।
- समान निर्भरता के उदाहरणों का पुन: उपयोग करने का कोई तरीका नहीं है। फिर, यह इस खिलौना अनुप्रयोग में महत्वपूर्ण नहीं है, लेकिन एक डेटाबेस कनेक्शन पर विचार करें। आपके पास आमतौर पर एक एकल उदाहरण होगा जो आपके आवेदन में साझा किया गया है।
अब, चलो इसे निर्भरता इंजेक्शन पैटर्न का उपयोग करने के लिए रिफ्लेक्टर करते हैं।
interface IHorn
{
void Honk();
}
class Horn : IHorn
{
public void Honk()
{
Console.WriteLine("beep!");
}
}
class Car
{
private IHorn horn;
public Car(IHorn horn)
{
this.horn = horn;
}
public void HonkHorn()
{
this.horn.Honk();
}
}
class Program
{
static void Main()
{
var horn = new Horn();
var car = new Car(horn);
car.HonkHorn();
}
}
हमने यहां दो प्रमुख बातें की हैं। सबसे पहले, हमने एक इंटरफ़ेस पेश किया है जो हमारी Horn
कक्षा में लागू होता है। यह Car
वर्ग को विशेष कार्यान्वयन के बजाय इंटरफ़ेस के लिए कोड देता है । अब कोड कुछ भी ले सकता है जो लागू करता है IHorn
। दूसरा, हमने हॉर्न इंस्टेंटेशन को बाहर निकाल दिया हैCar
और इसके बजाय इसे पास कर दिया है। यह ऊपर दिए गए मुद्दों को हल करता है और इसे विशिष्ट उदाहरणों और उनके जीवनचक्र को प्रबंधित करने के लिए एप्लिकेशन के मुख्य कार्य पर छोड़ देता है।
इसका मतलब यह है कि कार को छूने के लिए Car
वर्ग के बिना उपयोग करने के लिए एक नए प्रकार के सींग का परिचय दे सकता है :
class FrenchHorn : IHorn
{
public void Honk()
{
Console.WriteLine("le beep!");
}
}
मुख्य FrenchHorn
इसके बजाय कक्षा के एक उदाहरण को इंजेक्ट कर सकता है । यह भी नाटकीय रूप से परीक्षण को सरल करता है। आप यह MockHorn
सुनिश्चित करने के लिए Car
कंस्ट्रक्टर में इंजेक्ट करने के लिए एक वर्ग बना सकते हैं कि आप बस परीक्षण कर रहे हैंCar
अलगाव में कक्षा का ।
ऊपर दिया गया उदाहरण मैनुअल निर्भरता इंजेक्शन दिखाता है। आमतौर पर DI को एक फ्रेमवर्क के साथ किया जाता है (जैसे C # दुनिया में एकता या Ninject )। ये चौखटे आपकी निर्भरता ग्राफ के आधार पर आपके लिए निर्भरता की वायरिंग करेंगे और जरूरत के अनुसार इंस्टेंसेस बनाएंगे।
स्टैण्डर्ड नोड.जेएस वे
अब Node.js. में एक ही उदाहरण देखते हैं। हम शायद अपने कोड को 3 मॉड्यूल में तोड़ेंगे:
// horn.js
module.exports = {
honk: function () {
console.log("beep!");
}
};
// car.js
var horn = require("./horn");
module.exports = {
honkHorn: function () {
horn.honk();
}
};
// index.js
var car = require("./car");
car.honkHorn();
क्योंकि जावास्क्रिप्ट अप्रकाशित है, हमारे पास पहले जैसी ही चुस्त कपलिंग नहीं है। इंटरफेस की कोई आवश्यकता नहीं है (न ही वे मौजूद हैं) क्योंकि car
मॉड्यूल बस honk
जो कुछ भी है उस पर विधि को कॉल करने का प्रयास करेगाhorn
मॉड्यूल निर्यात ।
इसके अतिरिक्त, क्योंकि नोड का require
कैश सब कुछ है, मॉड्यूल अनिवार्य रूप से एक कंटेनर में संग्रहित एकल हैं। कोई अन्य मॉड्यूल जो require
ऑन पर कार्य करता हैhorn
को सटीक समान उदाहरण मिलेगा। यह डेटाबेस कनेक्शन जैसी एकल वस्तुओं को साझा करना बहुत आसान बनाता है।
अब भी मुद्दा है कि car
मॉड्यूल अपनी निर्भरता लाने के लिए जिम्मेदार है horn
। यदि आप चाहते थे कि कार अपने हॉर्न के लिए एक अलग मॉड्यूल का उपयोग करे, तो आपको मॉड्यूल require
में स्टेटमेंट बदलना होगा car
। यह करने के लिए एक बहुत ही सामान्य बात नहीं है, लेकिन यह परीक्षण के साथ मुद्दों का कारण बनता है।
लोगों को परीक्षण की समस्या से निपटने का सामान्य तरीका प्रॉक्सीवेर के साथ है । जावास्क्रिप्ट की गतिशील प्रकृति के कारण, प्रॉक्सी आपको कॉल करने और आपके द्वारा प्रदान किए गए किसी भी स्टब्स / मोक्स को वापस करने की आवश्यकता को स्वीकार करता है।
var proxyquire = require('proxyquire');
var hornStub = {
honk: function () {
console.log("test beep!");
}
};
var car = proxyquire('./car', { './horn': hornStub });
// Now make test assertions on car...
यह अधिकांश अनुप्रयोगों के लिए पर्याप्त से अधिक है। अगर यह आपके ऐप के लिए काम करता है तो इसके साथ जाएं। हालाँकि, मेरे अनुभव में जैसे-जैसे एप्लिकेशन बड़े और अधिक जटिल होते जाते हैं, इस तरह कोड बनाए रखना कठिन हो जाता है।
जावास्क्रिप्ट में DI
Node.js बहुत लचीला है। यदि आप उपरोक्त विधि से संतुष्ट नहीं हैं, तो आप निर्भरता इंजेक्शन पैटर्न का उपयोग करके अपने मॉड्यूल लिख सकते हैं। इस पैटर्न में, प्रत्येक मॉड्यूल एक फैक्ट्री फ़ंक्शन (या एक क्लास कंस्ट्रक्टर) का निर्यात करता है।
// horn.js
module.exports = function () {
return {
honk: function () {
console.log("beep!");
}
};
};
// car.js
module.exports = function (horn) {
return {
honkHorn: function () {
horn.honk();
}
};
};
// index.js
var horn = require("./horn")();
var car = require("./car")(horn);
car.honkHorn();
यह बहुत पहले C # विधि के अनुरूप है कि index.js
मॉड्यूल उदाहरण जीवन चक्र और तारों के लिए जिम्मेदार है। यूनिट परीक्षण काफी सरल है क्योंकि आप केवल कार्यों में मोक्स / स्टब्स में पास कर सकते हैं। फिर, अगर यह आपके आवेदन के लिए पर्याप्त है, तो इसके साथ जाएं।
बोलस डीआई फ्रेमवर्क
C # के विपरीत, आपके निर्भरता प्रबंधन के साथ मदद करने के लिए कोई स्थापित मानक DI चौखटे नहीं हैं। एनपीएम रजिस्ट्री में कई रूपरेखाएं हैं, लेकिन व्यापक रूप से किसी को भी गोद नहीं लिया गया है। इनमें से कई विकल्प पहले से ही अन्य उत्तरों में उद्धृत किए गए हैं।
मैं विशेष रूप से उपलब्ध किसी भी विकल्प से खुश नहीं था इसलिए मैंने अपना खुद का नाम बोलस लिखा । Bolus को ऊपर DI शैली में लिखे गए कोड के साथ काम करने के लिए डिज़ाइन किया गया है और यह बहुत DRY और बहुत सरल होने की कोशिश करता है । उपरोक्त समान car.js
और horn.js
मॉड्यूल का उपयोग करके , आप index.js
बोल्ट के साथ मॉड्यूल को फिर से लिख सकते हैं :
// index.js
var Injector = require("bolus");
var injector = new Injector();
injector.registerPath("**/*.js");
var car = injector.resolve("car");
car.honkHorn();
मूल विचार यह है कि आप एक इंजेक्टर बनाएँ। आप इंजेक्टर में अपने सभी मॉड्यूल रजिस्टर करते हैं। तब आप बस यह निर्धारित करते हैं कि आपको क्या चाहिए। बोल्टस निर्भरता ग्राफ को चलाएगा और आवश्यकतानुसार निर्भरता को बनाएगा और इंजेक्ट करेगा। आप इस तरह के एक खिलौना उदाहरण में ज्यादा बचत नहीं करते हैं, लेकिन जटिल निर्भरता वाले पेड़ों के साथ बड़े अनुप्रयोगों में बचत बहुत बड़ी है।
Bolus वैकल्पिक निर्भरता और परीक्षण ग्लोबल्स जैसी निफ्टी सुविधाओं के एक समूह का समर्थन करता है, लेकिन दो मानक लाभ हैं जो मैंने मानक Node.js दृष्टिकोण के सापेक्ष देखे हैं। सबसे पहले, यदि आपके पास बहुत सारे समान अनुप्रयोग हैं, तो आप अपने आधार के लिए एक निजी एनपीएम मॉड्यूल बना सकते हैं जो एक इंजेक्टर बनाता है और उस पर उपयोगी वस्तुओं को पंजीकृत करता है। फिर आपके विशिष्ट एप्लिकेशन जरूरत के अनुसार बहुत कुछ जोड़ सकते हैं, ओवरराइड कर सकते हैं और हल कर सकते हैं AngularJSइंजेक्टर काम करता है। दूसरा, आप निर्भरता के विभिन्न संदर्भों को प्रबंधित करने के लिए बोल्ट का उपयोग कर सकते हैं। उदाहरण के लिए, आप अनुरोध के अनुसार चाइल्ड इंजेक्टर बनाने के लिए मिडलवेयर का उपयोग कर सकते हैं, इंजेक्टर पर यूजर आईडी, सेशन आईडी, लॉगर इत्यादि को पंजीकृत कर सकते हैं, साथ ही उन पर निर्भर करता है। फिर अनुरोधों को पूरा करने के लिए आपको जो चाहिए वह हल करें। यह आपके अनुरोध के अनुसार आपको अपने मॉड्यूल के उदाहरण देता है और हर मॉड्यूल फ़ंक्शन कॉल के साथ लकड़हारा आदि को पास करने से रोकता है।