9.1 अवलंबित्व उलट

लक्षात ठेवा, आम्ही एकदा सांगितले होते की सर्व्हर ऍप्लिकेशनमध्ये तुम्ही फक्त प्रवाह तयार करू शकत नाही new Thread().start()? फक्त कंटेनरने धागे तयार केले पाहिजेत. आम्ही आता ही कल्पना आणखी विकसित करू.

सर्व वस्तू केवळ कंटेनरद्वारे तयार केल्या पाहिजेत . अर्थात, आम्ही सर्व वस्तूंबद्दल बोलत नाही, तर तथाकथित व्यावसायिक वस्तूंबद्दल बोलत आहोत. त्यांना बर्‍याचदा डब्बे असेही संबोधले जाते. या दृष्टिकोनाचे पाय SOLID च्या पाचव्या तत्त्वापासून वाढतात, ज्यासाठी वर्गांपासून मुक्त होणे आणि इंटरफेसवर जाणे आवश्यक आहे:

  • शीर्ष-स्तरीय मॉड्यूल्स निम्न-स्तरीय मॉड्यूल्सवर अवलंबून नसावेत. ते आणि इतर दोन्ही अमूर्तांवर अवलंबून असले पाहिजेत.
  • अॅब्स्ट्रॅक्शन तपशीलांवर अवलंबून नसावेत. अंमलबजावणी अमूर्ततेवर अवलंबून असणे आवश्यक आहे.

मॉड्यूल्समध्ये विशिष्ट अंमलबजावणीचे संदर्भ नसावेत आणि त्यांच्यातील सर्व अवलंबित्व आणि परस्परसंवाद केवळ अमूर्ततेच्या (म्हणजे इंटरफेस) आधारावर तयार केले जावेत. या नियमाचे सार एका वाक्यांशात लिहिले जाऊ शकते: सर्व अवलंबित्व इंटरफेसच्या स्वरूपात असणे आवश्यक आहे .

त्याचे मूलभूत स्वरूप आणि स्पष्ट साधेपणा असूनही, या नियमाचे बर्याचदा उल्लंघन केले जाते. उदाहरणार्थ, प्रत्येक वेळी जेव्हा आपण प्रोग्राम/मॉड्यूलच्या कोडमध्ये नवीन ऑपरेटर वापरतो आणि विशिष्ट प्रकारचा नवीन ऑब्जेक्ट तयार करतो, तेव्हा इंटरफेसवर अवलंबून न राहता, अंमलबजावणीवर अवलंबून राहते.

हे स्पष्ट आहे की हे टाळता येत नाही आणि वस्तू कुठेतरी तयार केल्या पाहिजेत. परंतु, कमीतकमी, आपल्याला हे जेथे केले गेले आहे आणि कोणत्या वर्गांमध्ये स्पष्टपणे निर्दिष्ट केले आहे त्या ठिकाणांची संख्या कमी करणे आवश्यक आहे, तसेच अशा ठिकाणांचे स्थानिकीकरण आणि विलगीकरण करणे आवश्यक आहे जेणेकरून ते प्रोग्राम कोडमध्ये विखुरले जाणार नाहीत.

विशेष वस्तू आणि मॉड्यूल - कारखाने, सर्व्हिस लोकेटर, आयओसी कंटेनर्समध्ये नवीन वस्तूंच्या निर्मितीवर लक्ष केंद्रित करण्याचा एक चांगला उपाय आहे.

एका अर्थाने, असा निर्णय सिंगल चॉईस प्रिन्सिपलला अनुसरतो, जे म्हणते: "जेव्हा जेव्हा सॉफ्टवेअर सिस्टमने अनेक पर्यायांना समर्थन दिले पाहिजे, तेव्हा त्यांची संपूर्ण यादी सिस्टमच्या फक्त एका मॉड्यूलला माहित असावी" .

म्हणूनच, भविष्यात नवीन पर्याय जोडणे आवश्यक असल्यास (किंवा नवीन अंमलबजावणी, जसे की आम्ही विचार करत असलेल्या नवीन वस्तू तयार करण्याच्या बाबतीत), तर ही माहिती असलेले मॉड्यूल आणि इतर सर्व मॉड्यूल अद्यतनित करणे पुरेसे आहे. अप्रभावित राहतील आणि नेहमीप्रमाणे त्यांचे कार्य चालू ठेवण्यास सक्षम असतील.

उदाहरण १

new ArrayList असे काहीतरी लिहिण्याऐवजी , List.new()JDK ने तुम्हाला लीफची योग्य अंमलबजावणी प्रदान करणे अर्थपूर्ण ठरेल : ArrayList, LinkedList, किंवा ConcurrentList.

उदाहरणार्थ, कंपाइलर पाहतो की वेगवेगळ्या थ्रेड्समधून ऑब्जेक्टला कॉल येत आहेत आणि तेथे थ्रेड-सेफ अंमलबजावणी ठेवतो. किंवा शीटच्या मध्यभागी खूप जास्त इन्सर्ट, नंतर अंमलबजावणी LinkedList वर आधारित असेल.

उदाहरण २

उदाहरणार्थ, हे याआधीच घडले आहे. संग्रह क्रमवारी लावण्यासाठी तुम्ही शेवटच्या वेळी सॉर्टिंग अल्गोरिदम कधी लिहिले होते? त्याऐवजी, आता प्रत्येकजण पद्धत वापरतो Collections.sort()आणि संग्रहातील घटकांनी तुलना करण्यायोग्य इंटरफेस (तुलना करण्यायोग्य) चे समर्थन केले पाहिजे.

जर sort()तुम्ही 10 पेक्षा कमी घटकांचा संग्रह या पद्धतीत पास केला, तर ते बबल सॉर्टने (बबल सॉर्ट) क्रमवारी लावणे शक्य आहे, क्विकसॉर्ट नाही.

उदाहरण ३

कंपाइलर तुम्ही स्ट्रिंग्स कसे जोडता ते आधीच पाहत आहे आणि तुमचा कोड सोबत बदलेल StringBuilder.append().

9.2 व्यवहारात अवलंबित्व उलथापालथ

आता सर्वात मनोरंजक: आपण सिद्धांत आणि सराव कसे एकत्र करू शकतो याचा विचार करूया. मॉड्युल्स त्यांची "अवलंबनता" योग्यरित्या कशी तयार आणि प्राप्त करू शकतात आणि अवलंबित्व उलट्याचे उल्लंघन करू शकत नाहीत?

हे करण्यासाठी, मॉड्यूल डिझाइन करताना, आपण स्वत: साठी निर्णय घेणे आवश्यक आहे:

  • मॉड्यूल काय करते, ते काय कार्य करते;
  • मग मॉड्यूलला त्याच्या वातावरणातून आवश्यक आहे, म्हणजे, त्याला कोणत्या वस्तू / मॉड्यूल्सचा सामना करावा लागेल;
  • आणि तो कसा मिळेल?

डिपेंडेंसी इन्व्हर्शनच्या तत्त्वांचे पालन करण्यासाठी, तुमचे मॉड्यूल कोणत्या बाह्य वस्तू वापरते आणि त्यांना त्यांचे संदर्भ कसे मिळतील हे निश्चितपणे ठरवावे लागेल.

आणि येथे खालील पर्याय आहेत:

  • मॉड्यूल स्वतः वस्तू तयार करते;
  • मॉड्यूल कंटेनरमधून वस्तू घेते;
  • वस्तू कोठून येतात हे मॉड्यूलला माहिती नाही.

समस्या अशी आहे की ऑब्जेक्ट तयार करण्यासाठी, आपल्याला विशिष्ट प्रकारच्या कन्स्ट्रक्टरला कॉल करणे आवश्यक आहे आणि परिणामी, मॉड्यूल इंटरफेसवर अवलंबून नाही तर विशिष्ट अंमलबजावणीवर अवलंबून असेल. परंतु जर आपल्याला मॉड्यूल कोडमध्ये ऑब्जेक्ट्स स्पष्टपणे तयार करायचे नसतील तर आपण फॅक्टरी मेथड पॅटर्न वापरू शकतो .

"मुख्य गोष्ट अशी आहे की नवीन द्वारे ऑब्जेक्ट थेट इन्स्टंट करण्याऐवजी, आम्ही क्लायंट क्लासला ऑब्जेक्ट्स तयार करण्यासाठी काही इंटरफेस प्रदान करतो. असा इंटरफेस नेहमी योग्य डिझाइनसह ओव्हरराइड केला जाऊ शकतो, कमी-स्तरीय मॉड्यूल वापरताना आम्हाला काही लवचिकता मिळते. उच्च-स्तरीय मॉड्यूल्समध्ये" .

ज्या प्रकरणांमध्ये संबंधित वस्तूंचे गट किंवा कुटुंबे तयार करणे आवश्यक आहे, तेथे फॅक्टरी पद्धतीऐवजी अमूर्त कारखाना वापरला जातो .

9.3 सर्व्हिस लोकेटर वापरणे

मॉड्यूल आवश्यक वस्तू ज्याच्याकडे आधीपासून आहे त्याच्याकडून घेते. असे गृहीत धरले जाते की सिस्टममध्ये ऑब्जेक्ट्सचे काही भांडार आहे, ज्यामध्ये मॉड्यूल त्यांच्या वस्तू "ठेवू" शकतात आणि रेपॉजिटरीमधून वस्तू "घेत" शकतात.

हा दृष्टिकोन सर्व्हिस लोकेटर पॅटर्नद्वारे अंमलात आणला जातो , ज्याची मुख्य कल्पना अशी आहे की प्रोग्राममध्ये एक ऑब्जेक्ट आहे ज्याला आवश्यक असलेल्या सर्व अवलंबन (सेवा) कसे मिळवायचे हे माहित आहे.

कारखान्यांतील मुख्य फरक असा आहे की सर्व्हिस लोकेटर ऑब्जेक्ट्स तयार करत नाही, परंतु प्रत्यक्षात आधीच इन्स्टंटेड ऑब्जेक्ट्स समाविष्ट करतात (किंवा ते कोठे / कसे मिळवायचे हे माहित आहे आणि जर ते तयार केले तर फक्त एकदाच पहिल्या कॉलवर). प्रत्येक कॉलवर फॅक्टरी एक नवीन ऑब्जेक्ट तयार करते ज्याची तुम्हाला पूर्ण मालकी मिळते आणि तुम्ही त्याद्वारे तुम्हाला हवे ते करू शकता.

महत्वाचे ! सर्व्हिस लोकेटर आधीपासून अस्तित्वात असलेल्या समान वस्तूंचे संदर्भ तयार करतो . म्हणून, सर्व्हिस लोकेटरने जारी केलेल्या वस्तूंबाबत तुम्ही अत्यंत सावधगिरी बाळगणे आवश्यक आहे, कारण तुमच्या सारख्याच वेळी कोणीतरी त्यांचा वापर करू शकते.

सर्व्हिस लोकेटरमधील ऑब्जेक्ट्स कॉन्फिगरेशन फाइलद्वारे थेट जोडल्या जाऊ शकतात आणि प्रोग्रामरसाठी कोणत्याही प्रकारे सोयीस्कर आहेत. सर्व्हिस लोकेटर हा स्टॅटिक पद्धतींचा संच, सिंगलटन किंवा इंटरफेससह एक स्टॅटिक क्लास असू शकतो आणि कन्स्ट्रक्टर किंवा पद्धतीद्वारे आवश्यक वर्गांमध्ये पास केला जाऊ शकतो.

सर्व्हिस लोकेटरला कधीकधी अँटी-पॅटर्न म्हटले जाते आणि त्याला परावृत्त केले जाते (कारण ते अंतर्निहित कनेक्शन तयार करते आणि केवळ चांगल्या डिझाइनचे स्वरूप देते). आपण मार्क सीमनकडून अधिक वाचू शकता:

9.4 अवलंबन इंजेक्शन

मॉड्यूल "खाण" अवलंबित्वांची अजिबात काळजी घेत नाही. हे फक्त ते ठरवते की त्याला काय काम करण्याची आवश्यकता आहे आणि सर्व आवश्यक अवलंबित्व बाहेरून कोणीतरी पुरवले जातात (परिचय)

यालाच म्हणतात - डिपेंडन्सी इंजेक्शन. सामान्यतः, आवश्यक अवलंबित्व एकतर कन्स्ट्रक्टर पॅरामीटर्स (कंस्ट्रक्टर इंजेक्शन) किंवा वर्ग पद्धतींद्वारे (सेटर इंजेक्शन) पास केले जातात.

हा दृष्टीकोन अवलंबित्व निर्माण करण्याच्या प्रक्रियेला उलट करतो - मॉड्यूल स्वतःऐवजी, अवलंबनांची निर्मिती बाहेरून एखाद्याद्वारे नियंत्रित केली जाते. ऑब्जेक्ट्सच्या सक्रिय उत्सर्जकाचे मॉड्यूल निष्क्रिय बनते - तो निर्माण करणारा नाही तर इतर त्याच्यासाठी तयार करतात.

या दिशेतील बदलाला इन्व्हर्शन ऑफ कंट्रोल , किंवा हॉलीवूड तत्त्व म्हणतात - "आम्हाला कॉल करू नका, आम्ही तुम्हाला कॉल करू."

हे सर्वात लवचिक समाधान आहे, जे मॉड्यूलला सर्वात मोठी स्वायत्तता देते . आम्ही असे म्हणू शकतो की केवळ ते "सिंगल रिस्पॉन्सिबिलिटी प्रिन्सिपल" पूर्णपणे अंमलात आणते - मॉड्यूल पूर्णपणे त्याचे काम चांगले करण्यावर केंद्रित असले पाहिजे आणि इतर कशाचीही चिंता न करता.

कामासाठी आवश्यक असलेल्या सर्व गोष्टींसह मॉड्यूल प्रदान करणे हे एक स्वतंत्र कार्य आहे, जे योग्य "तज्ञ" द्वारे हाताळले जावे (सामान्यतः विशिष्ट कंटेनर, एक IoC कंटेनर, अवलंबित्व व्यवस्थापित करण्यासाठी आणि त्यांच्या अंमलबजावणीसाठी जबाबदार आहे).

खरं तर, येथे सर्वकाही जीवनासारखे आहे: एका सुव्यवस्थित कंपनीमध्ये, प्रोग्रामर प्रोग्राम आणि डेस्क, संगणक आणि त्यांना कामासाठी आवश्यक असलेली प्रत्येक गोष्ट ऑफिस मॅनेजरद्वारे खरेदी केली जाते आणि प्रदान केली जाते. किंवा, जर तुम्ही प्रोग्रॅमचे रूपक कन्स्ट्रक्टर म्हणून वापरत असाल, तर मॉड्यूलने तारांचा विचार करू नये, कोणीतरी कन्स्ट्रक्टर एकत्र करण्यात गुंतलेले आहे, आणि स्वतःचे भाग नाही.

मॉड्यूल्समधील अवलंबनांचे वर्णन करण्यासाठी इंटरफेसचा वापर (डिपेंडेंसी इन्व्हर्शन) + या अवलंबनांची योग्य निर्मिती आणि इंजेक्शन (प्रामुख्याने डिपेंडन्सी इंजेक्शन) हे डिकपलिंगचे प्रमुख तंत्र आहेत असे म्हटल्यास अतिशयोक्ती होणार नाही .

ते एक पाया म्हणून काम करतात ज्यावर कोडची सैल जोडणी, त्याची लवचिकता, बदलांना प्रतिकार, पुनर्वापर आणि त्याशिवाय इतर सर्व तंत्रांचा फारसा अर्थ नाही. हा लूज कपलिंग आणि चांगल्या आर्किटेक्चरचा पाया आहे.

इन्व्हर्शन ऑफ कंट्रोल (डिपेंडन्सी इंजेक्शन आणि सर्व्हिस लोकेटरसह) च्या तत्त्वावर मार्टिन फॉलर यांनी तपशीलवार चर्चा केली आहे. त्यांच्या दोन्ही लेखांची भाषांतरे आहेत: "इन्व्हर्शन ऑफ कंट्रोल कंटेनर्स आणि द डिपेंडन्सी इंजेक्शन पॅटर्न" आणि "इन्व्हर्शन ऑफ कंट्रोल" .