क्या हम बिना कंस्ट्रक्टर के रह सकते हैं?


25

मान लें कि किसी कारण से सभी ऑब्जेक्ट इस तरह से बनाए गए हैं $ obj = CLASS :: getInstance ()। फिर हम बसने का उपयोग करके निर्भरता को इंजेक्ट करते हैं और $ obj-> initInstance () का उपयोग करके आरंभिक प्रदर्शन करते हैं; क्या कोई वास्तविक परेशानी या स्थितियां हैं, जिन्हें हल नहीं किया जा सकता है, अगर हम निर्माणकर्ताओं का उपयोग नहीं करेंगे?

इस तरह से ऑब्जेक्ट बनाने का कारण पीएस है, हम कुछ नियमों के अनुसार getInstance () के अंदर क्लास को बदल सकते हैं।

मैं PHP में काम कर रहा हूँ, अगर वह बात है


क्या प्रोग्रामिंग भाषा?
gnat

2
PHP (यह क्यों मायने रखता है?)
एक्सल फोले

8
ऐसा लगता है कि आप जो करना चाहते हैं उसे फैक्टरी पैटर्न का उपयोग करके प्राप्त किया जा सकता है।
सुपर

1
बस एक नोट के रूप में: फैक्ट्री पैटरन @superM का उल्लेख किया गया है, जो नियंत्रण के व्युत्क्रम को लागू करने का एक तरीका है (निर्भरता इंजेक्शन) एक और एक है।
जोकिम सॉयर

नहीं है कि मोटे तौर पर क्या वस्तुओं के साथ जावास्क्रिप्ट करता है?
थिज़र

जवाबों:


44

मैं कहूंगा कि यह आपके डिज़ाइन स्थान को गंभीर रूप से बाधित करता है।

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

उदाहरण के लिए, यदि प्रत्येक Fooवस्तु को जरूरत है Frobnicatorतो वह अपने निर्माता में जांच सकती है यदि वह Frobnicatorअशक्त है। यदि आप कंस्ट्रक्टर को हटा देते हैं, तो यह जांचना कठिन हो जाता है। क्या आप हर बिंदु पर जांच करते हैं कि इसका उपयोग कहां किया जाएगा? एक init()विधि में (प्रभावी रूप से कंस्ट्रक्टर विधि को बाहरी बनाना)? कभी इसकी जाँच करें और सर्वश्रेष्ठ की आशा करें?

हालांकि आप शायद अभी भी सब कुछ लागू कर सकते हैं (आखिरकार, आप अभी भी पूरा कर रहे हैं), कुछ चीजें करना बहुत कठिन होगा।

व्यक्तिगत रूप से मैं डिपेंडेंसी इंजेक्शन / नियंत्रण के व्युत्क्रम में देखने का सुझाव दूंगा । ये तकनीकें कंक्रीट कार्यान्वयन कक्षाओं को बदलने की अनुमति देती हैं, लेकिन वे रचनाकारों को लिखने / उपयोग करने से नहीं रोकती हैं।


"टूटी हुई" वस्तुओं के निर्माण से इनकार करने वाले "या सादे" से आपका क्या मतलब है?
गीक

2
@ गीक: एक कंस्ट्रक्टर अपने तर्क का निरीक्षण कर सकता है और यह तय कर सकता है कि क्या उन लोगों के पास काम करने वाली वस्तु होगी (उदाहरण के लिए यदि आपकी वस्तु को जरूरत है HttpClientतो यह जांचता है कि क्या वह पैरामीटर गैर-अशक्त है)। और अगर उन बाधाओं को पूरा नहीं किया जाता है, तो यह एक अपवाद फेंक सकता है। निर्माण-और-सेट-मान दृष्टिकोण के साथ वास्तव में संभव नहीं है।
जोआचिम सॉयर

1
मुझे लगता है कि ओपी केवल अंदर के निर्माण के बाहरीकरण का वर्णन कर रहा था init(), जो पूरी तरह से संभव है- हालांकि यह सिर्फ रखरखाव के बोझ को अधिक करता है।
पीटर

26

निर्माणकर्ताओं को 2 फायदे:

निर्माता किसी वस्तु के निर्माण के चरणों को परमाणु रूप से करने की अनुमति देते हैं।

मैं एक कंस्ट्रक्टर से बच सकता था और हर चीज के लिए सेटर्स का इस्तेमाल कर सकता था, लेकिन जोचिम सॉर ने सुझाव दिया कि अनिवार्य गुणों का क्या? एक निर्माता के साथ, एक ऑब्जेक्ट का अपना स्वयं का निर्माण तर्क होता है ताकि यह सुनिश्चित हो सके कि इस तरह के वर्ग के कोई अमान्य उदाहरण नहीं हैं

यदि Fooसेट करने के लिए 3 गुणों की आवश्यकता का एक उदाहरण बनाते हैं , तो निर्माता सभी 3 का संदर्भ ले सकता है, उन्हें मान्य कर सकता है और यदि वे अमान्य हैं तो एक अपवाद फेंक सकते हैं।

encapsulation

पूरी तरह से बसने वालों पर भरोसा करके, बोझ एक वस्तु के उपभोक्ता पर है कि वह इसे ठीक से बनाए। संपत्तियों के विभिन्न संयोजन हो सकते हैं जो मान्य हैं।

उदाहरण के लिए, हर Fooउदाहरण या तो का एक उदाहरण की जरूरत Barके रूप में संपत्ति barया का एक उदाहरण BarFinderके रूप में संपत्ति barFinder। यह या तो एक का उपयोग कर सकते हैं। आप मापदंडों के हर वैध सेट के लिए एक निर्माता बना सकते हैं और इस तरह से सम्मेलनों को लागू कर सकते हैं।

वस्तुओं के लिए तर्क और शब्दार्थ वस्तु के भीतर ही रहते हैं। यह अच्छा एनकैप्सुलेशन है।


15

हां, आप बिना कंस्ट्रक्टर के रह सकते हैं।

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

लेकिन नहीं, आपको अपने स्वयं के कंस्ट्रक्टरों की सख्त जरूरत नहीं है। बेशक, आपको कक्षाओं और वस्तुओं की सख्त जरूरत नहीं है।

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


पूर्ण रूप से। एक वर्ग और वस्तुओं के बिना भी रह सकता है, के साथ शुरू करने के लिए।
जेन्स जी

5
सभी ताकतवर असेंबलर की जय हो!
ददलू

9

कंस्ट्रक्टर्स का उपयोग करने का लाभ यह है कि वे यह सुनिश्चित करना आसान बनाते हैं कि आपके पास कभी भी अमान्य वस्तु नहीं होगी।

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

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

एक वर्कअराउंड केवल एक फैक्ट्री-पद्धति के माध्यम से वस्तुओं को बनाने के लिए हो सकता है जो कॉल करने वाले को वापस करने से पहले वैधता के लिए बनाई गई प्रत्येक वस्तु की जांच करता है।


3

$ obj = CLASS :: getInstance ()। फिर हम बसने का उपयोग करके निर्भरता को इंजेक्ट करते हैं और $ obj-> initInstance () का उपयोग करके आरंभिक प्रदर्शन करते हैं;

मुझे लगता है कि आप इसे और अधिक कठिन बना रहे हैं जितना इसे करने की आवश्यकता है। हम कंस्ट्रक्टर के माध्यम से निर्भरता को ठीक कर सकते हैं - और यदि आपके पास उनमें से बहुत कुछ है, तो बस एक शब्दकोश जैसी संरचना का उपयोग करें ताकि आप निर्दिष्ट कर सकें कि आप क्या उपयोग करना चाहते हैं:

$obj = new CLASS(array(
    'Frobnicator' => (),
    'Foonicator' => (),
));

और निर्माता के भीतर, आप इस तरह स्थिरता सुनिश्चित कर सकते हैं:

if (!array_key_exists('Frobnicator', $args)) {
    throw new Exception('Frobnicator required');
}
if (!array_key_exists('Foonicator', $args)) {
    $args['Foonicator'] = new DefaultFoonicator();
}

$args फिर निजी सदस्यों को आवश्यकतानुसार सेट करने के लिए उपयोग किया जा सकता है।

जब पूरी तरह से कंस्ट्रक्टर के भीतर ऐसा किया जाता है, तो एक मध्यवर्ती राज्य कभी नहीं होगा जहां $objमौजूद है लेकिन आरंभिक नहीं है, क्योंकि प्रश्न में वर्णित प्रणाली में होगा। इस तरह के मध्यवर्ती राज्यों से बचने के लिए बेहतर है, क्योंकि आप इस बात की गारंटी नहीं दे सकते हैं कि वस्तु हमेशा सही तरीके से उपयोग होने वाली है।


2

मैं वास्तव में इसी तरह की चीजों के बारे में सोच रहा था।

मैंने जो सवाल पूछा वह यह था कि "निर्माता क्या करता है, और क्या इसे अलग तरीके से करना संभव है?" मैं उन नतीजों पर पहुँचा:

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

  • यह सुनिश्चित करता है कि गुण मान्य हैं। यह आसानी से मुखर स्थिति द्वारा प्राप्त किया जा सकता है। फिर आप सिर्फ सही स्थितियों के साथ संपत्तियों को एनोटेट करेंगे। कुछ भाषाएँ पहले से ही ऐसा करती हैं।

  • कुछ और जटिल निर्माण तर्क। आधुनिक पैटर्न कंस्ट्रक्टर में ऐसा करने की अनुशंसा नहीं करते हैं, लेकिन विशेष कारखाने के तरीकों या कक्षाओं का उपयोग करने का प्रस्ताव करते हैं। इसलिए इस मामले में कंस्ट्रक्टर का उपयोग कम से कम है।

तो आपके प्रश्न का उत्तर देने के लिए: हाँ, मेरा मानना ​​है कि यह संभव है। लेकिन इसके लिए भाषा के डिजाइन में कुछ बड़े बदलावों की आवश्यकता होगी।

और मैंने अभी देखा कि मेरा उत्तर बहुत ओटी है।


2

हां, आप कंस्ट्रक्टरों का उपयोग किए बिना लगभग सब कुछ कर सकते हैं, लेकिन यह ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग भाषाओं के स्पष्ट रूप से व्यापक लाभ है।

आधुनिक भाषाओं में (मैं यहां C # के बारे में बात करूंगा जिसमें मैं प्रोग्राम करता हूं) आप कोड के कुछ हिस्सों को सीमित कर सकते हैं जो केवल एक कंस्ट्रक्टर में चलाए जा सकते हैं । जिसकी बदौलत आप भद्दी गलतियों से बच सकते हैं। इस तरह की एक चीज आसानी से संशोधित होती है:

public class A {
    readonly string rostring;

    public A(string arg) {
        rostring = arg;
    }

    public static A CreateInstance(string arg) {
        var result = new A();
        A.rostring = arg;  // < because of this the code won't compile!
        return result;
    }
}

जैसा कि पहले पढ़ा गया डिज़ाइनर पट्टर का उपयोग करने के बजाय जोकिम सॉयर ने सुझाया था । मैं मार्क सेमैन द्वारा .NET में निर्भरता इंजेक्शन पढ़ने की सलाह दूंगाFactoryDependency Injection


1

आवश्यकताओं के आधार पर एक प्रकार से किसी वस्तु को त्वरित करना संभव है। यह एक विशिष्ट प्रकार को वापस करने के लिए सिस्टम के वैश्विक चर का उपयोग करके स्वयं ही वस्तु हो सकता है।

हालांकि, कोड में एक वर्ग है जो "ऑल" हो सकता है वह है गतिशील प्रकार की अवधारणा । मेरा व्यक्तिगत रूप से मानना ​​है कि यह दृष्टिकोण आपके कोड में असंगति पैदा करता है, परीक्षण परिसरों को * बनाते हैं, और प्रस्तावित कार्य के प्रवाह के संबंध में "भविष्य अनिश्चित हो जाता है"।

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


1

दावा करने वाले कुछ अन्य उत्तरों को संतुलित करने के लिए:

एक कंस्ट्रक्टर आपको ऑब्जेक्ट के सभी सदस्य चर को एक वैध स्थिति में सेट करने का अवसर देता है ... आपके पास कभी भी अमान्य ऑब्जेक्ट नहीं होगा, जो आपको बहुत सारे कीड़े से बचाएगा।

तथा

एक निर्माता के साथ, एक ऑब्जेक्ट का अपना स्वयं का निर्माण तर्क होता है ताकि यह सुनिश्चित हो सके कि इस तरह के वर्ग के कोई अवैध उदाहरण नहीं हैं।

इस तरह के बयान कभी-कभी यह अनुमान लगाते हैं कि:

यदि किसी वर्ग के पास एक ऐसा कंस्ट्रक्टर होता है, जो उस समय तक बाहर निकल जाता है, तो उसने ऑब्जेक्ट को एक वैध स्थिति में डाल दिया है, और क्लास की कोई भी विधि उस स्थिति को उत्परिवर्तित नहीं करती है, तो किसी ऑब्जेक्ट का पता लगाने के लिए क्लास के बाहर कोड के लिए असंभव है। एक अमान्य स्थिति में उस वर्ग का।

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


0

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

जो कुछ भी स्थगित किया जा सकता है, मैं कंस्ट्रक्टर (आउटपुट मान आदि तैयार करना) से बाहर निकल जाता हूं। इस दृष्टिकोण के साथ, मुझे लगता है कि किसी भी चीज के लिए कंस्ट्रक्टर का उपयोग नहीं किया जाता है, लेकिन निर्भरता इंजेक्शन समझ में आता है।

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

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