2009-05-18 20 views
11

एक स्थिर निर्माता का उपयोग करने के लिए क्या फायदे हैं और यह कब उचित है?"नया" उपयोग करने के बजाय एक बनाएँ विधि क्यों है?

public class MyClass 
{ 
    protected MyClass() 
    { 
    } 

    public static MyClass Create() 
    { 
     return new MyClass(); 
    } 
} 

और उसके बाद के रूप में सिर्फ एक सार्वजनिक निर्माता होने और मैं पहली बार दृष्टिकोण देख सकते हैं

MyClass myClass = new MyClass(); 

का उपयोग कर वस्तुओं बनाने के लिए विरोध के माध्यम से

MyClass myClass = MyClass.Create(); 

वर्ग का उदाहरण बनाकर उपयोगी है यदि निर्माण विधि एक इंटरफ़ेस का एक उदाहरण देता है जो कक्षा लागू करता है ... यह कॉलर्स को विशिष्ट प्रकार के बजाय इंटरफ़ेस के उदाहरण बनाने के लिए मजबूर करेगा।

उत्तर

15

यह कारखाना पैटर्न है, और इसे अक्सर उप-वर्ग बनाने के लिए उपयोग किया जा सकता है, लेकिन पैरामीटर को स्थैतिक विधि को निर्धारित करने की अनुमति देता है कि कौन सा।

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

यदि ऑब्जेक्ट के सभी उदाहरणों को सृजन पर कैश किया जाना चाहिए या अन्यथा पंजीकृत होना आवश्यक है तो इसका भी उपयोग किया जा सकता है। यह सुनिश्चित करता है कि ग्राहक ऐसा करना न भूलें।

और निश्चित रूप से, यह सिंगलटन पैटर्न का हिस्सा और पार्सल है।

+1

मैं इस जवाब में रॉबर्ट पॉलसन के जवाब को "सरल सृजन से अधिक करने" के बारे में बता दूंगा क्योंकि यह इस उत्तर को पूरा करने के लिए प्रतीत होता है या कम से कम "उत्तर के कैश किए गए या अन्यथा पंजीकृत हिस्से" पर विस्तार करता है। –

1

यह पैटर्न आमतौर पर Singleton pattern में उपयोग किया जाता है। यह तब उपयोगी होता है जब आपके पास कक्षा के लिए कक्षा या मुखौटा होता है जिसे केवल एक कार्यक्रम के जीवन के दौरान तत्काल तत्काल किया जाना चाहिए, आमतौर पर संसाधनों का उपयोग करने वाले संसाधनों के कारण।

How to in C#

+2

सिंगलटन पैटर्न एक ही वस्तु का संदर्भ वापस करेगा, जबकि कारखाना पैटर्न कई उदाहरण बनाता है जो डेटा साझा कर सकते हैं। –

+1

बिलीओनेल का उल्लेख है, यह नहीं है- सिंगलटन पैटर्न; सिंगलटन कभी भी बनाए जाने के लिए कक्षा के केवल एक उदाहरण को मजबूर करता है। जब आप सिंगलटन पैटर्न का उपयोग करना चाहते हैं तो इसका एक शानदार उदाहरण सेटिंग कक्षाओं के लिए है जहां केवल एक होना चाहिए। –

+0

जबकि आप दोनों सही हैं और उनका कोड जरूरी नहीं है कि वे सिंगलोनोन को व्यक्त करें, कृपया याद रखें कि उनका मूल प्रश्न * स्थिर निर्माण * के उपयोग के आसपास घूमता है जो फैक्ट्री और सिंगलटन दोनों का उपयोग करता है। –

1

वहाँ विभिन्न कारणों से आप यह कर सकते हैं, उदाहरण के लिए हमेशा एक निश्चित वस्तु पूल (एक सिंगलटन वस्तु सहित) से एक उदाहरण वापस जाने के लिए कर रहे हैं, या के रूप में आप कहते हैं, एक अंतरफलक के उदाहरण वापस जाने के लिए।

लेकिन यदि आपके पास ऐसा करने का कोई स्पष्ट कारण नहीं है, तो नहीं।

2

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

एक उदाहरण एक वर्ग होगा जो डेटाबेस से कनेक्ट होता है - केवल एक कनेक्शन की आवश्यकता होती है, और कक्षा के सभी उदाहरणों द्वारा साझा की जा सकती है।

http://en.wikipedia.org/wiki/Factory_pattern

Billy3

+0

इसे फ़ैक्टरी विधि की आवश्यकता नहीं है। यह केवल एक स्थिर कनेक्शन चर के साथ पूरा किया जा सकता है। –

+0

सच है। लेकिन ऐसा नहीं है कि ओपी का कोड कैसे लिखा गया है। –

1

यह दृष्टिकोण अन्यथा इस दृष्टिकोण अपरंपरागत है केवल सामान्यतः Singletons के लिए इस्तेमाल किया है। तब तक उपयोग न करें जब तक कि आप समझें कि यह क्या करने का प्रयास कर रहा है।

+0

धन्यवाद जॉन, मुझे पता है कि कैसे, कब और क्यों सिंगलेट्स का उपयोग करना है, लेकिन मुझे पूरा यकीन है कि मैंने कोड नमूने देखे हैं जो इसका उपयोग सिंगलेट्स नहीं हैं ... वे निश्चित रूप से गलत हो सकते हैं इसलिए मैंने सवाल पूछा :-) –

+0

क्या उपयोग नहीं करते? सिंगलेट या स्थिर रचनाकार रचनात्मक पैटर्न। मैं पूर्व के साथ सहमत हूं (सिंगलेट से बचें) लेकिन अन्यथा असहमत होंगे। निर्माता/कारखाना पैटर्न काफी मानक है, और ओपी पूछ रहा है क्यों पैटर्न के उपयोग को समझने के लिए। –

1

यदि आप निजी कन्स्ट्रक्टर का उपयोग करते हैं, तो MyClass को अंतिम होने के लिए मजबूर करने का यह एक अच्छा तरीका है। इस तरह सबक्लास को नहीं बनाया जा सकता है, क्योंकि उनके कन्स्ट्रक्टर सुपर के कन्स्ट्रक्टर तक नहीं पहुंच सकते हैं।

एक और फायदा यह है कि जब आपके पास कन्स्ट्रक्टर के लिए एक पैरामीटर होता है।तो फिर तुम नामित तर्क की नकल के साथ निर्माण नाम कर सकते हैं:

public static MyClass createWithDays(int days) { 
... 
} 

अब तुलना new MyClass(5)MyClass.createWithDays(5)

8

लिए यह एक सिंगलटन नहीं है ... एक ही उदाहरण हर बार वापसी होगी अगर यह था बनाएँ।

यह एक कारखाना पैटर्न है। मैं सामान्य रूप से नहीं इंटरफेस वर्गों के साथ ऐसा होता है, इसलिए मैं यहाँ फैलाने के लिए है, लेकिन एक काल्पनिक उदाहरण होगा:

public static MyClass Create() 
{ 
    if(OS == Windows) 
     return new MyDerivedClassForWindows(); 
    else if(OS == Linux) 
     return new MyDerivedClassForLinux(); 
    etc.... 
} 
+0

क्या आप MyClass या IMyClass को वापस कर देंगे ... MyClass का मानना ​​एक इंटरफ़ेस नहीं है लेकिन IMyClass है (मेरा मतलब है कि यह सिर्फ सम्मेलन है लेकिन आप मेरा बिंदु देखते हैं)। –

+0

मैं IMyClass वापस कर दूंगा। मैक लोग संभवतः माई क्लास (केवल अलग होने के लिए) से प्राप्त नहीं करना चाहते हैं, लेकिन अगर वे मेरे सैंडबॉक्स में खेलना चाहते हैं तो उन्हें कम से कम IMyClass लागू करना होगा। – ratchetr

1
अलावा जब यह एक सिंगलटन है, एक "स्थिर कारखाने विधि" जैसे MyClass.Create हो सकता होने से

उपयोगी अगर MyClass.Create लागू करने वाला व्यक्ति MyClass का उप-वर्ग वापस करना चाहता है ... उदाहरण के लिए परीक्षण के दौरान यह MyClassWithExtraTestingFunctionality सबक्लास ... या कॉन्फ़िगरेशन विकल्प के आधार पर MyClassBeingRemotedOverTheNetwork सबक्लास का एक उदाहरण लौटा सकता है ..

0

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

1

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

यदि लागू किया गया है तो यह विचार बहुत कमजोर युग्मित सिस्टम का कारण बन सकता है, जिसे आसानी से तैनाती या यहां तक ​​कि रनटाइम के बाद बदला जा सकता है। हालांकि, जटिलता बढ़ जाती है क्योंकि आपके पास एक और स्तर का संकेत है।

3

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

Guid g = new guid();

Guid.Empty होगा। जाहिर है, आप एक नया गइड बनाने की क्षमता चाहते हैं जो यादृच्छिक है, इसलिए Guid.NewGuid() विधि ऐसा करने का एक तरीका है।

+0

ग्रिड क्लास बहुत खराब नामकरण-वार है - स्पष्ट रूप से नामित न्यूगुइड() एक नया (यादृच्छिक) ग्रिड बनाने का एकमात्र तरीका है जो कि रचनाकारों के विपरीत है जो मौजूदा डेटा से केवल ग्रिड बनाते हैं। आपका उत्तर वास्तविकता को देखता है, लेकिन सवाल का जवाब क्यों नहीं देता है। ग्रिड क्लास में खराब नामकरण के बावजूद, आपको इस बारे में सोचना होगा कि क्यों Guid.NewGuid() नए ग्रिड() से अलग है। –

1

एक स्थिर कन्स्ट्रक्टर भी आपके कन्स्ट्रक्टर को अधिक स्पष्ट नाम देने का एक अच्छा तरीका है। यह डिफ़ॉल्ट पैरामीटर

पूर्व के लिए उपयोगी भी हो सकता है: Myclass.create(); नई MyClass की intead (defaultParam1, defaultParam2 ...)

यहोशू बलोच effective Java (मद 1)

4

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

सिंगलटन पैटर्न

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

public class MySingletonClass 
{ 
    private MySingletonClass currentInstance = null; 

    public MySingletonClass CreateInstance() 
    { 
     if (currentInstance == null) 
     { 
       currentInstance = new MySingletonClass(); 
     } 
     else 
     { 
       return currentInstance; 
     } 
    } 
} 

फैक्टरी पैटर्न

कारखाने पैटर्न ठोस वर्ग का सार निर्माण के लिए एक महान अवसर है, उदाहरण के लिए, आइए मान लें कि आपके पास कुछ एक्सएमएल है, और एक्सएमएल में आप कौन सी नोड (नोडे, नोडेब, या नोडसी) देखते हैं, आपके पास एक अलग वर्ग है जो इसे संसाधित करेगा। उदाहरण:

public class MyXmlProcessorFactory 
{ 
    public static IMyXmlProcessor GetMyXmlProcessor(XmlDocument document) 
    { 
     XmlNode rootNode = document.DocumentElement; 

     if (rootNode.SelectSingleNode("NodeA") != null) 
     { 
       return new NodeAMyXmlProcessor(); 
     } 
     else if (rootNode.SelectSingleNode("NodeB") != null) 
     { 
       return new NodeBMyXmlProcessor(); 
     } 
     else if (rootNode.SelectSingleNode("NodeC") != null) 
     { 
       return new NodeCMyXmlProcessor(); 
     } 
     else 
     { 
       return new DefaultMyXmlProcessor(); 
     } 
    } 
} 
3

आप सही हैं। यह सिंगलटन पैटर्न नहीं है। यह एक फैक्टरी पैटर्न है।

public class User 
{ 
    public int id; 
    public string userName; 
    public string password; 
    public string role; 

    private User() { } 

    public static User CreateByCredentials(string uid, string pwd) 
    { 
     User user = new User(); 
     user.userName = uid; 
     user.password = pwd; 
     return user; 
    } 

    public static User CreateById(int id) 
    { 
     User user = new User(); 
     user.id = id; 
     return user; 
    } 

} 

इस दृष्टिकोण के लिए दो फायदे हैं: बनाएँ की

उपयोग करें (बजाय नई देता है) आप इस प्रकार उपयोगकर्ता और अधिक स्पष्टता

दे रही है इस जैसे लो तरीकों के सार्थक नाम देने के लिए अनुमति देता है : (। यह या सभी मामलों में उपयोगी नहीं हो सकता)

  1. हम एक अशक्त वस्तु है, जो एक निर्माता के साथ क्या करना असंभव है लौट सकते हैं
  2. यदि ऑब्जेक्ट बनाने के कई तरीके हैं, तो यह आपको अधिक सार्थक फ़ंक्शन नाम प्रदान करने का मौका देता है। उदाहरण में आपके पास User.CreateByCredentials (स्ट्रिंग उपयोगकर्ता नाम, स्ट्रिंग पासवर्ड) & उपयोगकर्ता। CREateById (int id)। आप कन्स्ट्रक्टर ओवरलोडिंग के साथ समान कार्यक्षमता को पूरा कर सकते हैं, लेकिन शायद ही कभी स्पष्टता के साथ।
2

अधिक औपचारिक रूप से, यह आमतौर पर के रूप में Replace Constructor with Factory Method

आप जब आप एक वस्तु बनाने के सरल निर्माण की तुलना में अधिक क्या करना चाहते करने के लिए भेजा है।

यानी फैक्ट्री विधि का उपयोग करके, आप अधिक स्पष्ट हो सकते हैं, और एक सरल निर्माता पर कोड के लिए और अधिक सृजन विकल्प उपलब्ध हो सकते हैं।

मैं किताब Refactoring:Improving the Design of Existing Code (Fowler)

0

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

इसके अलावा @Rashmi पंडित ने लिखा है:

public static User CreateByCredentials(string uid, string pwd) 
    { 
     .... 
    } 

    public static User CreateById(int id) 
    { 
    ... 
    } 

आपकी प्रतिक्रिया करने के लिए, तुम सिर्फ बजाय दो अलग-अलग बनाने के तरीकों बनाने के विभिन्न विधि हस्ताक्षरों के साथ अतिभारित कंस्ट्रक्टर्स उपयोग नहीं कर सकते?

+0

आलसी लोडिंग क्रिएशनल पैटर्न से प्रभावित नहीं है। कोड पठनीयता दृश्य से, @ रश्मी का कोड स्वयं दस्तावेज है, जहां रचनाकार नए उपयोगकर्ता (स्ट्रिंग, स्ट्रिंग) या नए उपयोगकर्ता (int) काफी सहज नहीं हैं। –

0

ध्यान दें कि आप कन्स्ट्रक्टर दृष्टिकोण का उपयोग करते समय केवल निर्माता का उपयोग शुरू कर सकते हैं।

public void Example() 
    { 
     var person = new Person 
         { 
          GivenName = "John", 
          FamilyName = "Smith", 
          Address = new Address 
              { 
               Street = "Wallace", 
               Number = 12 
              }, 
          PhoneNumbers = new List<PhoneNumber> 
               { 
                new PhoneNumber 
                 { 
                  Number = 1234234, 
                  AreaCode = 02 
                 }, 
                new PhoneNumber 
                 { 
                  Number = 1234234, AreaCode = 02 
                 } 
               } 
         }; 
    } 

    internal class PhoneNumber 
    { 
     public int AreaCode { get; set; } 

     public int Number { get; set; } 
    } 

    internal class Address 
    { 
     public int Number { get; set; } 

     public string Street { get; set; } 
    } 

    internal class Person 
    { 
     public Address Address { get; set; } 

     public string GivenName { get; set; } 

     public string FamilyName { get; set; } 

     public List<PhoneNumber> PhoneNumbers { get; set; } 
    } 
} 
संबंधित मुद्दे