निर्भरता इंजेक्शन और सिंगलटन डिजाइन पैटर्न


88

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

उदाहरण के लिए लकड़हारा। मैं इसका उपयोग कर सकता था Logger.GetInstance().Log(...) , लेकिन इसके बजाय, मुझे लकड़हारा के उदाहरण के साथ, मेरे द्वारा बनाई गई प्रत्येक कक्षा को इंजेक्ट करने की आवश्यकता क्यों है?

जवाबों:


65

यदि आप यह सत्यापित करना चाहते हैं कि परीक्षण में क्या लॉग किया गया है, तो आपको निर्भरता इंजेक्शन की आवश्यकता है। इसके अलावा, एक लकड़हारा शायद ही कभी एक सिंगलटन है - आम तौर पर आपके पास प्रत्येक वर्ग में एक लकड़हारा होता है।

परीक्षण-योग्यता के लिए ऑब्जेक्ट-ओरिएंटेड डिज़ाइन पर इस प्रस्तुति को देखें और आप देखेंगे कि सिंगलनेट खराब क्यों हैं।

एकल के साथ समस्या यह है कि वे एक वैश्विक स्थिति का प्रतिनिधित्व करते हैं जो भविष्यवाणी करना कठिन है, खासकर परीक्षणों में।

ध्यान रखें कि एक वस्तु de-facto सिंगलटन हो सकती है लेकिन फिर भी निर्भरता-इंजेक्शन के माध्यम से प्राप्त की जा सकती है, बजाय Singleton.getInstance()

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


89

सिंगलटन साम्यवाद की तरह हैं: वे दोनों कागज पर बहुत अच्छे लगते हैं, लेकिन व्यवहार में समस्याओं के साथ विस्फोट करते हैं।

सिंगलटन पैटर्न वस्तुओं तक पहुंचने में आसानी पर एक अनिवार्य जोर देता है। यह पूरी तरह से संदर्भ की आवश्यकता को पूरा करता है कि प्रत्येक उपभोक्ता एक AppDomain-scoped ऑब्जेक्ट का उपयोग करता है, जिसमें कार्यान्वयन को अलग करने के लिए कोई विकल्प नहीं है। यह GetInstance()बिल्कुल शून्य अभिव्यंजक शक्ति को जोड़ते हुए आपकी कक्षाओं में अवसंरचना ज्ञान (कॉल ) को एम्बेड करता है । यह वास्तव में आपकी अभिव्यंजक शक्ति को कम करता है, क्योंकि आप उन सभी के लिए इसे बदले बिना एक वर्ग द्वारा उपयोग किए जाने वाले कार्यान्वयन को नहीं बदल सकते । आप केवल कार्यक्षमता के एक-बंद टुकड़े को नहीं जोड़ सकते।

इसके अलावा, जब वर्ग Fooनिर्भर करता है Logger.GetInstance(), Fooप्रभावी रूप से उपभोक्ताओं से अपनी निर्भरता छिपा रहा है। इसका मतलब है कि आप इसे पूरी तरह से समझ नहीं सकते हैं Fooया इसे आत्मविश्वास के साथ उपयोग नहीं कर सकते हैं जब तक कि आप इसके स्रोत को नहीं पढ़ते हैं और इस तथ्य को उजागर करते हैं कि यह निर्भर करता है Logger। यदि आपके पास स्रोत नहीं है, तो आप कितनी अच्छी तरह समझ सकते हैं और प्रभावी ढंग से उस कोड का उपयोग कर सकते हैं, जिस पर आप निर्भर हैं।

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


9
@BryanWatts ने कहा कि सभी, सिंगलटन अभी भी बहुत तेज हैं और सामान्य मध्यम स्तर के अनुप्रयोग में कम त्रुटि है। सामान्य तौर पर मेरे पास एक (कस्टम) लकड़हारे के लिए एक से अधिक संभावित कार्यान्वयन नहीं है, इसलिए मुझे ** की आवश्यकता क्यों होगी: 1. उस के लिए एक इंटरफ़ेस बनाएं और इसे हर बार बदलने के लिए मुझे सार्वजनिक सदस्यों को जोड़ने / बदलने की आवश्यकता है 2. बनाए रखें DI कॉन्फ़िगरेशन 3. इस तथ्य को छिपाएं कि पूरी प्रणाली में इस प्रकार का एक ही ऑब्जेक्ट है 4. एक समयपूर्व पृथक्करण की चिंताओं के कारण एक सख्त कार्यक्षमता से खुद को बांधें।
उरी अब्रामसन

@UriAbramson: ऐसा लगता है कि आपने पहले से तय किए गए ट्रेडऑफ के बारे में निर्णय ले लिया है, इसलिए मैं आपको समझाने की कोशिश नहीं करूंगा।
ब्रायन वॉट्स

@BryanWatts इसका मामला नहीं है, शायद मेरी टिप्पणी थोड़ी कठोर थी, लेकिन यह वास्तव में मुझे यह सुनने के लिए बहुत दिलचस्पी है कि आपको मेरे द्वारा लाए गए बिंदु के बारे में क्या कहना है ...
उरी अब्रामसन

1
@ यूरीब्रैम्सन: पर्याप्त मेला। क्या आप कम से कम सहमत होंगे कि परीक्षण के दौरान अलगाव के लिए कार्यान्वयन की अदला-बदली महत्वपूर्ण है?
ब्रायन वॉट्स

5
एकल और निर्भरता इंजेक्शन का उपयोग पारस्परिक रूप से अनन्य नहीं है। एक सिंगलटन एक इंटरफ़ेस को लागू कर सकता है, इसलिए इसका उपयोग किसी अन्य वर्ग पर निर्भरता को संतुष्ट करने के लिए किया जा सकता है। तथ्य यह है कि यह एक सिंगलटन है, हर उपभोक्ता को "GetInstance" विधि / संपत्ति के माध्यम से एक संदर्भ प्राप्त करने के लिए मजबूर नहीं करता है।
ओलिवर

18

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

आईएमओ आमतौर पर एक सिंगलटन लॉगर एक चिंता का विषय नहीं है, क्योंकि इसमें आपके द्वारा परीक्षण किए जा रहे वर्ग से संबंधित कोई भी राज्य शामिल नहीं है। यही है, लकड़हारा राज्य (और इसके संभावित परिवर्तन) का परीक्षण की स्थिति पर कोई प्रभाव नहीं पड़ता है। तो यह आपकी इकाई परीक्षणों को और अधिक कठिन नहीं बनाता है।

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

तो मेरी लब्बोलुआब यह है: एक वर्ग जो (लगभग) सार्वभौमिक रूप से उपयोग किया जाता है, लेकिन आपके ऐप के लिए प्रासंगिक नहीं है, सुरक्षित रूप से सिंगलटन के रूप में लागू किया जा सकता है


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

4
@kyoryu, मैं "सामान्य" मामले के बारे में बात कर रहा हूं, जो आईएमएचओ का अर्थ है एक (डी फैक्टो) मानक लॉगिंग फ्रेमवर्क का उपयोग करना। (जो आम तौर पर संपत्ति / XML फ़ाइलों btw के माध्यम से विन्यास कर रहे हैं।) बेशक वहाँ अपवाद हैं - हमेशा की तरह। अगर मुझे पता है कि मेरा ऐप इस संबंध में असाधारण है, तो मैं वास्तव में एक सिंगलटन का उपयोग नहीं करूंगा। लेकिन यह कहते हुए कि "यह कुछ समय के लिए उपयोगी हो सकता है" लगभग हमेशा बर्बाद होने वाला प्रयास है।
पेटर तोर्क

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

1
@kyoryu, गलत धारणा के लिए खेद है। मैंने एक नीच और एक टिप्पणी देखी, इसलिए मैंने डॉट्स - गलत तरीके से जोड़ा, जैसा कि यह पता चला है :-( मैंने कभी भी एक अलग लॉगिंग ढांचे में स्विच करने की आवश्यकता का अनुभव नहीं किया है, लेकिन फिर, मैं समझता हूं कि यह एक वैध हो सकता है। कुछ परियोजनाओं में चिंता की बात है।
Péter Török

5
अगर मैं गलत हूं तो मुझे सुधारो, लेकिन सिंगलटन लोगफैक्टरी के लिए होगा, लकड़हारे के लिए नहीं। प्लस LogFactory एपाचे कॉमन्स या Slf4j लॉगिंग मुखौटा होने की संभावना है। तो लॉगिंग कार्यान्वयन को स्विच करना वैसे भी दर्द रहित होता है। क्या डीआईएफ का उपयोग करने के लिए डीआई के साथ वास्तविक दर्द नहीं है इस तथ्य को स्वीकार करने के लिए कि आपको अपने ऐप में हर उदाहरण बनाने के लिए अब एप्लिकेशनकनेक्ट पर जाना होगा?
एचडीवी १

9

यह ज्यादातर है, लेकिन परीक्षणों के बारे में नहीं। सिंगटेलटन लोकप्रिय थे क्योंकि उनका उपभोग करना आसान था, लेकिन सिंगलनेट्स के लिए डाउनसाइड्स की संख्या है।

  • कठिन परीक्षा है। मतलब मैं कैसे सुनिश्चित करूं कि लकड़हारा सही काम करे।
  • के साथ परीक्षण करना कठिन है। मतलब अगर मैं कोड का परीक्षण कर रहा हूं जो लकड़हारे का उपयोग करता है, लेकिन यह मेरे परीक्षण का ध्यान केंद्रित नहीं है, मुझे अभी भी अपने परीक्षण को सुनिश्चित करने की आवश्यकता है कि एनवी का समर्थन करता है
  • कभी-कभी आप एक सिंगलटन नहीं चाहते हैं, लेकिन अधिक flexibilty

DI आपको अपने आश्रित वर्गों की आसान खपत देता है - बस इसे कंस्ट्रक्टर आर्ग में डालें, और सिस्टम आपको परीक्षण और निर्माण लचीलापन प्रदान करते हुए आपके लिए प्रदान करता है।


ज़रुरी नहीं। यह साझा किए जाने योग्य राज्य और स्थिर निर्भरता के बारे में है जो लंबे समय में चीजों को दर्दनाक बनाता है। परीक्षण केवल स्पष्ट है, और अक्सर सबसे दर्दनाक, उदाहरण।
kyoryu

2

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

एक सिंगलटन के लिए आंत की जांच होनी चाहिए "क्या मैं ठीक होऊंगा अगर यह सिंगलटन के बजाय एक वैश्विक चर था?" यदि नहीं, तो आप ग्लोबल वैरिएबल पर पेपर करने के लिए सिंगलटन पैटर्न का उपयोग कर रहे हैं, और एक अलग दृष्टिकोण पर विचार करना चाहिए।


1

बस मोनोस्टेट लेख की जाँच की - यह सिंगलटन के लिए एक अच्छा विकल्प है, लेकिन इसमें कुछ अजीब गुण हैं:

class Mono{
    public static $db;
    public function setDb($db){
       self::$db = $db;
    }

}

class Mapper extends Mono{
    //mapping procedure
    return $Entity;

    public function save($Entity);//requires database connection to be set
}

class Entity{
public function save(){
    $Mapper = new Mapper();
    $Mapper->save($this);//has same static reference to database class     
}

$Mapper = new Mapper();
$Mapper->setDb($db);

$User = $Mapper->find(1);
$User->save();

इस तरह की डरावनी नहीं है - क्योंकि मैपर वास्तव में बचाने के लिए डेटाबेस कनेक्शन पर निर्भर है () - लेकिन अगर पहले एक और मैपर बनाया गया है - यह निर्भरता प्राप्त करने में इस कदम को छोड़ सकता है। साफ-सुथरा रहते हुए, यह भी गन्दा नहीं है?


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