एक कंस्ट्रक्टर कितना जटिल होना चाहिए


18

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

दूसरे क्या सोचते हैं? मैं C # का उपयोग कर रहा हूँ अगर इससे कोई फर्क पड़ता है।

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

कंस्ट्रक्टर्स को किसी ऑब्जेक्ट के क्षेत्र को तुरंत करना चाहिए और ऑब्जेक्ट को उपयोग करने के लिए तैयार करने के लिए आवश्यक किसी अन्य इनिशियलाइज़ेशन को करना चाहिए। यह आम तौर पर इसका मतलब है कि निर्माणकर्ता छोटे हैं, लेकिन ऐसे परिदृश्य हैं जहां यह पर्याप्त मात्रा में काम होगा।


8
मैं असहमत हूं। निर्भरता उलटा सिद्धांत पर एक नजर है, यह बेहतर होगा यदि ऑब्जेक्ट ए को कंस्ट्रक्टर में एक मान्य राज्य में ऑब्जेक्ट बी को सौंप दिया जाए।
जिमी होफा

5
क्या आप पूछ रहे हैं कि कितना किया जा सकता है? कितना किया जाना चाहिए? या आपकी विशिष्ट स्थिति कितनी होनी चाहिए? यह तीन बहुत अलग सवाल है।
बोब्सन

1
मैं निर्भरता इंजेक्शन (या "निर्भरता उलटा") को देखने के लिए जिमी हॉफ के सुझाव से सहमत हूं। यह विवरण पढ़ने पर मेरा पहला विचार था, क्योंकि ऐसा लगता है कि आप पहले से ही आधे रास्ते में हैं; आपके पास पहले से ही कार्यक्षमता वर्ग ए में अलग हो गई है, जो वर्ग बी का उपयोग कर रहा है। मैं आपके मामले में बात नहीं कर सकता, लेकिन मुझे आमतौर पर लगता है कि निर्भरता इंजेक्शन पैटर्न का उपयोग करने के लिए रीफैक्टरिंग कोड कक्षाओं को सरल / कम intertwined बनाता है।
डॉ। विली के अपरेंटिस

1
बोबसन, मैंने शीर्षक को 'चाहिए' में बदल दिया। मैं यहां सर्वश्रेष्ठ अभ्यास के लिए कह रहा हूं।
ताईन किम

1
@ जिमीहॉफ: शायद आपको अपनी टिप्पणी का जवाब में विस्तार करना चाहिए।
केविन क्लाइन

जवाबों:


22

आपका प्रश्न दो पूरी तरह से अलग भागों से बना है:

क्या मुझे कंस्ट्रक्टर से अपवाद फेंकना चाहिए, या क्या मुझे विधि विफल होनी चाहिए?

यह स्पष्ट रूप से फेल-फास्ट सिद्धांत का अनुप्रयोग है । कंस्ट्रक्टर को फेल करना बहुत आसान है क्योंकि यह डिबग करने की तुलना में डिबग करना आसान है कि विधि विफल क्यों हो रही है। उदाहरण के लिए, हो सकता है कि आपको कोड के किसी अन्य भाग से पहले से बनाया गया उदाहरण मिल जाए और कॉलिंग के तरीकों से आपको त्रुटियाँ मिलें। क्या यह स्पष्ट है कि वस्तु गलत बनाई गई है? नहीं।

"कोशिश / पकड़ में कॉल लपेटो" समस्या के रूप में। अपवाद असाधारण होने के लिए हैं । यदि आप जानते हैं कि कुछ कोड अपवाद को फेंक देंगे, तो आप कोड को कोशिश / पकड़ में नहीं लपेटेंगे, लेकिन आप उस कोड को निष्पादित करने से पहले उस कोड के मापदंडों को मान्य करते हैं जो अपवाद को फेंक सकता है। अपवाद केवल व्यवस्था को अमान्य स्थिति में लाने के लिए सुनिश्चित करने के तरीके के रूप में हैं। यदि आप जानते हैं कि कुछ इनपुट पैरामीटर अमान्य स्थिति को जन्म दे सकते हैं, तो आप सुनिश्चित करें कि वे पैरामीटर कभी नहीं होते हैं। इस तरह, आपको केवल उन स्थानों पर प्रयास / कैच करना होगा, जहाँ आप तार्किक रूप से उस अपवाद को संभाल सकते हैं, जो आमतौर पर सिस्टम की सीमा पर होता है।

क्या मैं कंस्ट्रक्टर से "सिस्टम के अन्य भागों, जैसे DB" को एक्सेस कर सकता हूं।

मुझे लगता है कि यह कम से कम विस्मय के सिद्धांत के खिलाफ है । बहुत से लोग उम्मीद नहीं करेंगे कि कंस्ट्रक्टर डीबी तक पहुंच बना सकता है। तो नहीं, आपको ऐसा नहीं करना चाहिए।


2
इसका अधिक उपयुक्त समाधान आमतौर पर एक "ओपन" प्रकार की विधि को जोड़ना है जहां निर्माण मुफ्त है, लेकिन आपके द्वारा "ओपन" / "कनेक्ट" / आदि से पहले कोई उपयोग नहीं किया जा सकता है, जहां सभी वास्तविक प्रारंभ होता है। जब आप भविष्य में वस्तुओं का आंशिक निर्माण करना चाहते हैं, तो एक उपयोगी क्षमता है।
१a:

@ जिमीहॉफ मुझे निर्माण की विधि और निर्माण के लिए विशिष्ट विधि के बीच कोई अंतर नहीं दिखता है।
व्यंग्यात्मक

4
आप नहीं कर सकते हैं, लेकिन कई करते हैं। जब आप कनेक्शन ऑब्जेक्ट बनाते हैं, तो इसके बारे में सोचें कि क्या निर्माता इसे जोड़ता है? यदि यह जुड़ा नहीं है तो क्या वस्तु प्रयोग करने योग्य है? दोनों प्रश्नों में उत्तर नहीं है, क्योंकि यह कनेक्शन ऑब्जेक्ट्स को आंशिक रूप से निर्मित करने के लिए सहायक है ताकि आप कनेक्शन खोलने से पहले सेटिंग्स और चीजों को ट्विक कर सकें। यह इस परिदृश्य के लिए एक सामान्य दृष्टिकोण है। मुझे अभी भी लगता है कि कंस्ट्रक्टर इंजेक्शन उन परिदृश्यों के लिए सही दृष्टिकोण है जहां ऑब्जेक्ट ए में एक संसाधन निर्भरता है लेकिन एक खुली विधि अभी भी बेहतर है कि कंस्ट्रक्टर खतरनाक काम कर रहा है।
जिमी होफा

@ जिमीहॉफ लेकिन कनेक्शन वर्ग की विशिष्ट आवश्यकता है, ओओपी डिजाइन का सामान्य नियम नहीं। मैं वास्तव में इसे नियम से असाधारण मामला कहूंगा। आप मूल रूप से बिल्डर पैटर्न के बारे में बात कर रहे हैं।
व्यंग्यात्मक

2
यह एक आवश्यकता नहीं है, यह एक डिजाइन निर्णय था। वे निर्माणकर्ता को एक कनेक्शन स्ट्रिंग ले सकते थे और निर्माण होने पर तुरंत कनेक्ट कर सकते थे। उन्होंने फैसला नहीं किया क्योंकि यह ऑब्जेक्ट बनाने में सक्षम होने के लिए सहायक है, फिर कनेक्शन स्ट्रिंग या अन्य बिट्स और बॉबबल्स को ट्वीक करें और इसे बाद में कनेक्ट करें ,
जिमी हॉफ

19

ओह।

एक कंस्ट्रक्टर को जितना संभव हो उतना कम करना चाहिए - यह मुद्दा कि कंस्ट्रक्टरों में अपवाद व्यवहार अजीब है। बहुत कम प्रोग्रामर जानते हैं कि उचित व्यवहार क्या है (इनहेरिटेंस परिदृश्यों सहित), और अपने उपयोगकर्ताओं को हर एक पल की कोशिश / पकड़ने के लिए मजबूर करना ... सबसे अच्छा है।

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

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


2
जटिल निर्माण परिदृश्य ठीक वैसा ही है जैसा कि आपके यहाँ उल्लेखित रचनात्मक पैटर्न मौजूद हैं। यह इन समस्याग्रस्त निर्माणों के लिए एक अच्छा दृष्टिकोण है। मुझे यह सोचने के लिए दिया जाता है कि .NET में कोई Connectionवस्तु CreateCommandआपके लिए कैसे हो सकती है ताकि आप जान सकें कि कमांड उचित रूप से जुड़ा हुआ है।
जिमी होफा

2
इसमें मैं यह जोड़ूंगा कि एक डेटाबेस एक भारी बाहरी निर्भरता है, मान लीजिए कि आप भविष्य में किसी बिंदु पर डेटाबेस को स्विच करना चाहते हैं (या परीक्षण के लिए एक वस्तु का मज़ाक उड़ाते हैं), इस तरह के कोड को फैक्ट्री क्लास (या आईएसईएसआर की तरह) स्थानांतरित करना प्रदाता) एक क्लीनर दृष्टिकोण की तरह लगता है
जेसन स्पर्सके 18

4
क्या आप "निर्माणकर्ताओं में अपवाद व्यवहार अजीब है" पर विस्तार से बता सकते हैं? यदि आप क्रिएट का उपयोग करते हैं, तो क्या आपको इसे पकड़ने की कोशिश में लपेटने की ज़रूरत नहीं है जैसे आप कंस्ट्रक्टर को कॉल लपेटेंगे? मुझे ऐसा लगता है कि Create, कंस्ट्रक्टर के लिए सिर्फ अलग नाम है। शायद मुझे आपका जवाब सही नहीं मिल रहा है?
ताईन किम

1
कंस्ट्रक्शनर्स से बुदबुदाती अपवादों को पकड़ने की कोशिश की थी, इस के खिलाफ तर्क के लिए +1। हालांकि "कंस्ट्रक्टर में कोई काम नहीं" कहने वाले लोगों के साथ काम करने से यह कुछ अजीब पैटर्न भी बना सकता है। मैंने कोड देखा है जहां हर वस्तु का न केवल एक निर्माता है, बल्कि एक इनिशियलाइज़ () का कुछ रूप भी है, जहाँ अनुमान लगाते हैं? ऑब्जेक्ट वास्तव में मान्य नहीं है जब तक कि उसे या तो नहीं बुलाया जाता है। और फिर आपके पास कॉल करने के लिए दो चीजें हैं: ctor और Initialize ()। किसी ऑब्जेक्ट को सेट करने के लिए कार्य करने की समस्या गायब नहीं होती है - C # C ++ की तुलना में अलग-अलग समाधान प्राप्त कर सकता है। कारखाने अच्छे हैं!
जे त्राना

1
@jtrana - हाँ, इनिशियलाइज़ अच्छा नहीं है। कंस्ट्रक्टर कुछ सेंस डिफॉल्ट या फैक्ट्री के लिए इनिशियलाइज़ करता है या मेथड क्रिएट करता है और एक यूज़ेबल इंस्टेंस देता है।
तेलस्टिन

1

कंस्ट्रक्टर - विधि जटिलता संतुलन वास्तव में अच्छे स्टाइल के बारे में चर्चा का विषय है। अधिक जटिल चीजों के लिए Class() {}एक विधि के साथ, अक्सर खाली कंस्ट्रक्टर का उपयोग किया जाता है Init(..) {..}। तर्कों को ध्यान में रखते हुए:

  • कक्षा क्रमांकन संभावना
  • कंस्ट्रक्टर से पृथक्करण विधि के साथ, आपको अक्सर एक ही क्रम को Class x = new Class(); x.Init(..);कई बार दोहराने की आवश्यकता होती है , आंशिक रूप से यूनिट टेस्ट में। इतना अच्छा नहीं है, हालांकि, पढ़ने के लिए क्रिस्टल स्पष्ट है। कभी-कभी, मैंने उन्हें कोड की एक पंक्ति में रखा।
  • जब यूनिट टेस्ट का उद्देश्य सिर्फ क्लास इनिशियलाइज़ेशन टेस्ट होता है, तो बेहतर होता है कि खुद में इनिट हो, और अधिक जटिल क्रियाओं को एक-एक करके पूरा करने के लिए, इंटरमीडिएट एसेर्स के साथ।

लाभ, मेरी राय में, initविधि की यह है कि विफलता से निपटना बहुत आसान है। विशेष रूप से, initविधि का रिटर्न मान इंगित कर सकता है कि क्या आरंभीकरण सफल है, और विधि यह सुनिश्चित कर सकती है कि वस्तु हमेशा एक अच्छी स्थिति में हो।
pqnet
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.