कंस्ट्रक्टर फ़ंक्शन बनाम फ़ैक्टरी फ़ंक्शन


150

क्या कोई निर्माता फ़ंक्शन और जावास्क्रिप्ट में फ़ैक्टरी फ़ंक्शन के बीच अंतर को स्पष्ट कर सकता है।

दूसरे के बजाय एक का उपयोग कब करें?

जवाबों:


149

मूल अंतर यह है कि एक कंस्ट्रक्टर फ़ंक्शन का उपयोग newकीवर्ड के साथ किया जाता है (जिसके कारण जावास्क्रिप्ट स्वचालित रूप से एक नया ऑब्जेक्ट बनाने के लिए, thisउस ऑब्जेक्ट पर फ़ंक्शन के भीतर सेट होता है, और ऑब्जेक्ट वापस कर देता है):

var objFromConstructor = new ConstructorFunction();

एक फैक्ट्री फ़ंक्शन को "नियमित" फ़ंक्शन की तरह कहा जाता है:

var objFromFactory = factoryFunction();

लेकिन इसे "फ़ैक्टरी" मानने के लिए किसी वस्तु का नया उदाहरण वापस करने की आवश्यकता होगी: यदि आप इसे सिर्फ बूलियन या कुछ लौटाते हैं, तो आप इसे "फ़ैक्टरी" फ़ंक्शन नहीं कहेंगे। ऐसा अपने आप नहीं होता है new, लेकिन यह कुछ मामलों के लिए अधिक लचीलापन देता है।

वास्तव में सरल उदाहरण में ऊपर उल्लिखित कार्य कुछ इस तरह दिख सकते हैं:

function ConstructorFunction() {
   this.someProp1 = "1";
   this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };

function factoryFunction() {
   var obj = {
      someProp1 : "1",
      someProp2 : "2",
      someMethod: function() { /* whatever */ }
   };
   // other code to manipulate obj in some way here
   return obj;
}

बेशक आप कारखाने के कार्यों को उस सरल उदाहरण की तुलना में बहुत अधिक जटिल बना सकते हैं।

फ़ैक्टरी फ़ंक्शंस का एक फ़ायदा यह है कि लौटाए जाने वाले ऑब्जेक्ट कुछ पैरामीटर के आधार पर कई अलग-अलग प्रकार के हो सकते हैं।


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

6
मैं यह बताना चाहता था कि दोनों मामलों (निर्माण कार्य बनाम कारखाना समारोह) के लिए उदाहरण सुसंगत होना चाहिए। फ़ैक्टरी फ़ंक्शन के लिए उदाहरण में फ़ैक्टरी someMethodद्वारा लौटाए गए ऑब्जेक्ट्स के लिए शामिल नहीं है , और यही वह जगह है जहां यह थोड़ा धूमिल हो जाता है। फैक्ट्री फ़ंक्शन के अंदर, यदि कोई बस करता है var obj = { ... , someMethod: function() {}, ... }, तो वह प्रत्येक वस्तु को वापस लौटा देगा someMethodजिसकी एक अलग प्रति है जो कुछ ऐसा है जो हम नहीं चाहते हैं। यह वह जगह है जहाँ कारखाने के कार्य का उपयोग newऔर prototypeअंदर मदद मिलेगी।
भरत खत्री

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

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

1
@ फ़ेडरिको - फैक्ट्री के तरीकों को सिर्फ एक सादे वस्तु पर वापस जाने की ज़रूरत नहीं है। वे newआंतरिक रूप से उपयोग कर सकते हैं , या Object.create()किसी विशिष्ट प्रोटोटाइप के साथ एक ऑब्जेक्ट बनाने के लिए उपयोग कर सकते हैं ।
nnnnnn

110

कंस्ट्रक्टर का उपयोग करने के लाभ

  • अधिकांश पुस्तकें आपको कंस्ट्रक्टर का उपयोग करना सिखाती हैं और new

  • this नई वस्तु को संदर्भित करता है

  • कुछ लोग var myFoo = new Foo();पढ़ना पसंद करते हैं ।

कमियां

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

  • भूल newइस तरह के एक सामान्य बग है, आपको यह सुनिश्चित करने के लिए बॉयलरप्लेट की जांच को जोड़ने पर जोर देना चाहिए कि कंस्ट्रक्टर को सही तरीके से कहा जाता है ( if (!(this instanceof Foo)) { return new Foo() })। EDIT: ES6 (ES2015) के बाद से आप newएक classकंस्ट्रक्टर के साथ भूल नहीं सकते हैं , या कंस्ट्रक्टर एक त्रुटि को फेंक देगा।

  • यदि आप instanceofजांच करते हैं, तो यह अस्पष्टता छोड़ देता है कि क्या newआवश्यक है या नहीं । मेरी राय में, यह नहीं होना चाहिए। आपने newआवश्यकता को प्रभावी ढंग से कम कर दिया है , जिसका अर्थ है कि आप ड्राबैक # 1 मिटा सकते हैं। लेकिन तब आपको अतिरिक्त बॉयलरप्लेट, एक कैपिटल लेटर, और कम लचीले thisसंदर्भ के साथ सिर्फ एक फैक्ट्री फंक्शन मिला है

कंस्ट्रक्टर खुले / बंद सिद्धांत को तोड़ते हैं

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

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

इसके अलावा, कंस्ट्रक्टरों का उपयोग आपको एक भ्रामक देता है instanceofजो निष्पादन संदर्भों में काम नहीं करता है, और यह काम नहीं करता है यदि आपका निर्माता प्रोटोटाइप बाहर हो जाता है। यह भी विफल हो जाएगा यदि आप thisअपने निर्माता से वापस लौटना शुरू करते हैं , और फिर एक मनमानी वस्तु निर्यात करने के लिए स्विच करते हैं, जो आपको अपने निर्माता में कारखाने की तरह व्यवहार को सक्षम करने के लिए करना होगा।

कारखानों का उपयोग करने के लाभ

  • कम कोड - कोई बॉयलरप्लेट आवश्यक नहीं है।

  • आप किसी भी मनमानी वस्तु को वापस कर सकते हैं, और किसी भी मनमाने ढंग से प्रोटोटाइप का उपयोग कर सकते हैं - आपको विभिन्न प्रकार की वस्तुओं को बनाने के लिए अधिक लचीलापन देता है जो एक ही एपीआई को लागू करते हैं। उदाहरण के लिए, एक मीडिया प्लेयर जो एचटीएमएल 5 और फ्लैश प्लेयर, या एक इवेंट लाइब्रेरी दोनों का उदाहरण बना सकता है, जो डोम इवेंट्स या वेब सॉकेट इवेंट्स का उत्सर्जन कर सकता है। फैक्ट्रियां निष्पादन के संदर्भों में वस्तुओं को तुरंत रोक सकती हैं, ऑब्जेक्ट पूल का लाभ उठा सकती हैं, और अधिक लचीले प्रोटोटाइप के उत्तराधिकार मॉडल के लिए अनुमति दे सकती हैं।

  • आपको कभी भी एक कारखाने से एक कंस्ट्रक्टर में बदलने की आवश्यकता नहीं होगी, इसलिए रिफैक्टिंग एक मुद्दा कभी नहीं होगा।

  • उपयोग करने के बारे में कोई अस्पष्टता नहीं new। मत करो। (यह thisबुरा व्यवहार करेगा , अगले बिंदु देखें)।

  • thisसामान्य रूप से ऐसा व्यवहार करता है - इसलिए आप इसका उपयोग मूल वस्तु तक पहुंचने के लिए कर सकते हैं (उदाहरण के लिए, अंदर player.create(), thisसंदर्भित करता है player, ठीक उसी तरह जैसे कोई अन्य विधि मंगलाचरण होगा। callऔर साथ applyही पुन: असाइन करें this, जैसा कि अपेक्षित है। यदि आप मूल ऑब्जेक्ट पर प्रोटोटाइप स्टोर करते हैं, तो। गतिशील रूप से कार्यक्षमता की अदला-बदली करने का एक शानदार तरीका हो सकता है, और अपनी वस्तु की तात्कालिकता के लिए बहुत लचीले बहुरूपता को सक्षम कर सकता है।

  • पूंजी लगाना या नहीं, इसके बारे में कोई अस्पष्टता नहीं। मत करो। लिंट उपकरण शिकायत करेंगे, और फिर आप का उपयोग करने की कोशिश newकरेंगे, और फिर आप ऊपर वर्णित लाभ को पूर्ववत करेंगे।

  • कुछ लोगों को रास्ता पसंद है var myFoo = foo();या var myFoo = foo.create();पढ़ता है।

कमियां

  • newअपेक्षानुसार व्यवहार नहीं करता (ऊपर देखें)। समाधान: इसका उपयोग न करें।

  • thisनई वस्तु का उल्लेख नहीं करता (बजाय, अगर निर्माता डॉट नोटेशन या वर्ग कोष्ठक अंकन, जैसे foo.bar () के साथ शुरू हो जाती है - thisको संदर्भित करता है fooहर दूसरे JavaScript विधि की तरह - - लाभ देखें)।


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

4
ओपन / बंद के उल्लंघन के बारे में: यह सब निर्भरता इंजेक्शन के बारे में नहीं है? यदि A को B की आवश्यकता है, तो A को नए B () या A कॉल BFactory.create () कॉल करें, दोनों ही युग्मन का परिचय देते हैं। अगर दूसरी तरफ आप कंपोजीशन रूट में A का B का उदाहरण देते हैं, तो A को इस बात के बारे में कुछ भी जानने की आवश्यकता नहीं है कि B का त्वरित मूल्यांकन कैसे किया जाता है। मुझे लगता है कि निर्माता और कारखाने दोनों के उपयोग हैं; कंस्ट्रक्टर सरल तात्कालिकता के लिए हैं, अधिक जटिल तात्कालिकता के लिए कारखाने हैं। लेकिन दोनों ही मामलों में, अपनी निर्भरता को इंजेक्ट करना बुद्धिमानी है।
स्टीफन बिलियट

1
DI राज्य को इंजेक्ट करने के लिए अच्छा है: कॉन्फ़िगरेशन, डोमेन ऑब्जेक्ट्स, और इसी तरह। यह सब कुछ के लिए overkill है।
एरिक इलियट

1
उपद्रव यह है कि आवश्यक newखुले / बंद सिद्धांत का उल्लंघन करता है। इन टिप्पणियों की अनुमति की तुलना में बहुत बड़ी चर्चा के लिए मध्यम.com/javascript-scene/… देखें ।
एरिक इलियट 2

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

39

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


5

एक कंस्ट्रक्टर फ़ंक्शन उदाहरण

function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User("Jack");
  • newएक वस्तु बनाता है पर प्रोटोटाइप बनाया और उसके मूल्य के रूप में बनाया वस्तु के साथ User.prototypeकहता है ।Userthis

  • new वैकल्पिक के रूप में अपने ऑपरेंड के लिए एक तर्क अभिव्यक्ति का व्यवहार करता है:

         let user = new User;

    कोई तर्क के साथ newकॉल करने का कारण होगा User

  • newबनाई गई वस्तु को तब तक लौटाता है , जब तक कि निर्माता वस्तु का मूल्य नहीं लौटाता है , जो बदले में लौटा दिया जाता है। यह एक किनारे का मामला है जिसे अधिकांश भाग के लिए नजरअंदाज किया जा सकता है।

फायदा और नुकसान

कंस्ट्रक्टर फ़ंक्शन द्वारा बनाई गई ऑब्जेक्ट्स कंस्ट्रक्टर की prototypeसंपत्ति से गुण प्राप्त करती हैं, और instanceOfनिर्माता फ़ंक्शन पर ऑपरेटर का उपयोग करके सही लौटाता है ।

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

extendsकीवर्ड का उपयोग करके कंस्ट्रक्टर कार्यों को बढ़ाया जा सकता है ।

कन्स्ट्रक्टर फ़ंक्शंस nullत्रुटि मान के रूप में वापस नहीं आ सकते । चूंकि यह ऑब्जेक्ट डेटा प्रकार नहीं है, इसलिए इसे अनदेखा कर दिया जाता है new

एक फैक्टरी फ़ंक्शन उदाहरण

function User(name, age) {
  return {
    name,
    age,
  }
};

let user = User("Tom", 23);

यहां फैक्ट्री फ़ंक्शन को बिना बुलाया जाता है new। यह फ़ंक्शन प्रत्यक्ष या अप्रत्यक्ष उपयोग के लिए पूरी तरह से जिम्मेदार है यदि इसके तर्क और वस्तु का प्रकार यह वापस आ जाता है। इस उदाहरण में यह तर्कों से निर्धारित कुछ गुणों के साथ एक सरल [वस्तु वस्तु] देता है।

फायदा और नुकसान

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

फ़ैक्टरी फ़ंक्शन को हमेशा एक ही प्रकार की वस्तुओं को वापस करने की आवश्यकता नहीं होती है, और यहां तक ​​कि nullत्रुटि संकेतक के रूप में भी लौट सकते हैं ।

सरल मामलों में, कारखाने के कार्य संरचना और अर्थ में सरल हो सकते हैं।

आमतौर पर लौटे ऑब्जेक्ट फैक्ट्री फ़ंक्शन की prototypeसंपत्ति से विरासत में नहीं मिलते हैं, और से लौटते falseहैं instanceOf factoryFunction

फैक्ट्री फ़ंक्शन को extendsकीवर्ड का उपयोग करके सुरक्षित रूप से विस्तारित नहीं किया जा सकता है, क्योंकि फैक्ट्री फ़ंक्शन द्वारा उपयोग किए गए कंस्ट्रक्टर prototypeकी prototypeसंपत्ति के बजाय विस्तारित ऑब्जेक्ट फैक्ट्री फ़ंक्शंस प्रॉपर्टी से वारिस होंगे ।


1
यह उसी विषय पर इस प्रश्न के उत्तर में पोस्ट किया गया एक उत्तर है ,
traktor53

न केवल "अशक्त", बल्कि "नया" भी किसी भी प्रीमेच्योर डेटाटाइप को अनदेखा कर देगा जो कि अवरोधक फ़ंक्शन द्वारा लौटाया गया है।
विशाल

2

फैक्टरियां हमेशा "बेहतर" होती हैं। तब ऑब्जेक्ट ओरिएंटेड भाषाओं का उपयोग करते हुए

  1. अनुबंध पर निर्णय (तरीके और वे क्या करेंगे)
  2. उन तरीकों को उजागर करने वाले इंटरफेस बनाएं (जावास्क्रिप्ट में आपके पास इंटरफेस नहीं है ताकि आपको चेकिंग के कुछ तरीके के साथ आने की आवश्यकता हो)
  3. एक फैक्ट्री बनाएं जिसमें आवश्यक प्रत्येक इंटरफ़ेस का कार्यान्वयन हो।

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

फैक्टरियां - बाकी सभी चीज़ों से बेहतर - वसंत की रूपरेखा पूरी तरह से इस विचार के आसपास बनाई गई है।


फैक्ट्री हर लाइन को बदलने की इस समस्या को कैसे हल करती है?
कोड नाम जैक

0

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

जब आप कॉटर्स और कारखानों के बीच निर्णय लेते हैं, तो आपको यह तय करने की आवश्यकता होती है कि क्या जटिलता लाभ द्वारा उचित है।

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


5
जावास्क्रिप्ट में, निर्माताओं का उपयोग करने की लागत कारखानों का उपयोग करने की लागत से अधिक है क्योंकि जेएस में कोई भी फ़ंक्शन एक नई वस्तु वापस कर सकता है। कंस्ट्रक्टर्स इसके द्वारा जटिलता जोड़ते हैं: आवश्यक new, व्यवहार में परिवर्तन this, रिटर्न वैल्यू को बदलना, एक प्रोटोटाइप रेफ को कनेक्ट करना, सक्षम करना instanceof(जो झूठ है और इस उद्देश्य के लिए इसका उपयोग नहीं किया जाना चाहिए)। मूल रूप से, वे सभी "सुविधाएँ" हैं। व्यवहार में, वे आपके कोड की गुणवत्ता पर चोट करते हैं।
एरिक इलियट

0

मतभेदों के लिए, एरिक इलियट ने स्पष्ट रूप से स्पष्ट किया,

लेकिन दूसरे प्रश्न के लिए:

दूसरे के बजाय एक का उपयोग कब करें?

यदि आप ऑब्जेक्ट-ओरिएंटेड बैकग्राउंड से आ रहे हैं, तो कंस्ट्रक्टर फ़ंक्शन आपके लिए अधिक स्वाभाविक लगता है। इस तरह आपको newकीवर्ड का उपयोग करना नहीं भूलना चाहिए ।

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