C # में फ़ैक्टरी पैटर्न: एक वस्तु उदाहरण सुनिश्चित करने के लिए केवल एक फ़ैक्टरी वर्ग द्वारा कैसे बनाया जा सकता है?


93

हाल ही में मैं अपने कुछ कोड हासिल करने के बारे में सोच रहा हूं। मैं उत्सुक हूं कि कोई यह कैसे सुनिश्चित कर सकता है कि कोई वस्तु कभी भी सीधे नहीं बनाई जा सकती है, लेकिन केवल एक कारखाने वर्ग के कुछ तरीके के माध्यम से। हम कहते हैं कि मेरे पास कुछ "व्यावसायिक वस्तु" वर्ग है और मैं यह सुनिश्चित करना चाहता हूं कि इस वर्ग के किसी भी उदाहरण में एक वैध आंतरिक स्थिति होगी। इसे प्राप्त करने के लिए मुझे एक वस्तु बनाने से पहले कुछ जाँच करने की आवश्यकता होगी, शायद इसके निर्माता में। यह सब ठीक है जब तक मैं तय नहीं करता कि मैं इस चेक को व्यापार तर्क का हिस्सा बनाना चाहता हूं। तो, मैं अपने व्यावसायिक तर्क वर्ग में केवल किसी विधि के माध्यम से किसी व्यावसायिक वस्तु को कैसे बनाए जाने की व्यवस्था कर सकता हूं लेकिन कभी सीधे नहीं? C ++ के पुराने "मित्र" कीवर्ड का उपयोग करने की पहली प्राकृतिक इच्छा C # के साथ कम हो जाएगी। इसलिए हमें अन्य विकल्पों की आवश्यकता है ...

आइए कुछ उदाहरण देखें:

public MyBusinessObjectClass
{
    public string MyProperty { get; private set; }

    public MyBusinessObjectClass (string myProperty)
    {
        MyProperty = myProperty;
    }
}

public MyBusinessLogicClass
{
    public MyBusinessObjectClass CreateBusinessObject (string myProperty)
    {
        // Perform some check on myProperty

        if (true /* check is okay */)
            return new MyBusinessObjectClass (myProperty);

        return null;
    }
}

यह सब ठीक है जब तक आपको याद है कि आप इनपुट की जांच किए बिना सीधे MyBusinessObjectClass उदाहरण बना सकते हैं। मैं उस तकनीकी संभावना को पूरी तरह से बाहर करना चाहूंगा।

तो, समुदाय इस बारे में क्या सोचता है?


MyBoClass विधि गलत है?
pradeeptp

2
मैं असमंजस में हूं, आप क्यों नहीं चाहेंगे कि आपके व्यवसाय की वस्तुएं अपने स्वयं के आक्रमणकारियों की रक्षा के लिए जिम्मेदार हों? फैक्ट्री पैटर्न का बिंदु (जैसा कि मैं इसे समझता हूं) या तो ए के लिए है) कई निर्भरताओं के साथ एक जटिल वर्ग के निर्माण के साथ सौदा या बी) कारखाने को केवल एक इंटरफ़ेस या सार को उजागर करने के लिए क्या रनटाइम प्रकार वापस करने का निर्णय लेने दें ग्राहक के लिए वर्ग। अपने व्यावसायिक नियमों को अपने व्यावसायिक वस्तुओं में रखना OOP का बहुत ही आवश्यक है।
सारा

@kai सही है, व्यावसायिक वस्तु इसके अतिक्रमण से बचाने के लिए जिम्मेदार है, लेकिन कंस्ट्रक्टर कॉलर यह सुनिश्चित करने के लिए है कि उन्हें कंस्ट्रक्टर में पास करने से पहले तर्क मान्य हों ! CreateBusinessObjectविधि का उद्देश्य तर्कों को मान्य करना है (किसी नई वैध वस्तु को वापस करना या किसी त्रुटि को वापस करना) एकल कॉल में तब होता है जब एक कॉलर को तुरंत पता नहीं चलता कि क्या तर्क कंस्ट्रक्टर में पारित होने के लिए मान्य हैं।
लाइटमैन

2
मैं असहमत हूं। निर्माणकर्ता दिए गए मापदंडों के लिए कोई भी आवश्यक जांच करने के लिए जिम्मेदार है। यदि मैं एक निर्माता को कॉल करता हूं और कोई अपवाद नहीं फेंका जाता है, तो मुझे विश्वास है कि बनाई गई वस्तु एक मान्य स्थिति में है। "गलत" तर्कों का उपयोग करके किसी वर्ग को तत्काल करना संभव नहीं होना चाहिए। Distanceएक नकारात्मक तर्क के साथ एक उदाहरण बनाना उदाहरण के ArgumentOutOfRangeExceptionलिए फेंकना चाहिए , आप एक DistanceFactoryही चेक बनाने से कुछ नहीं हासिल करेंगे। मैं अब भी नहीं देखता कि आप यहाँ क्या हासिल करने के लिए खड़े हैं।
सारा

जवाबों:


55

ऐसा लगता है कि आप केवल ऑब्जेक्ट बनाने से पहले कुछ व्यावसायिक तर्क चलाना चाहते हैं - तो आप "BusinessClass" के अंदर एक स्थिर पद्धति क्यों नहीं बनाते हैं, जो सभी गंदे "myProperty" कार्य की जाँच करता है, और कंस्ट्रक्टर को निजी बनाता है?

public BusinessClass
{
    public string MyProperty { get; private set; }

    private BusinessClass()
    {
    }

    private BusinessClass(string myProperty)
    {
        MyProperty = myProperty;
    }

    public static BusinessClass CreateObject(string myProperty)
    {
        // Perform some check on myProperty

        if (/* all ok */)
            return new BusinessClass(myProperty);

        return null;
    }
}

इसे कॉल करना बहुत सरल होगा:

BusinessClass objBusiness = BusinessClass.CreateObject(someProperty);

6
आह, आप अशक्त लौटने के बजाय एक अपवाद भी फेंक सकते हैं।
रिकार्डो नोल्डे

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

इंटरफ़ेस / सार आधार वर्ग के माध्यम से इस वास्तुकला की आवश्यकता के लिए कोई अच्छा तरीका है? यानी एक इंटरफ़ेस / अमूर्त आधार वर्ग जो यह तय करता है कि कार्यान्वयनकर्ताओं को एक ctor को उजागर नहीं करना चाहिए।
अराश मोटामेदी

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

66

आप कंस्ट्रक्टर को निजी बना सकते हैं, और कारखाने को नेस्टेड प्रकार:

public class BusinessObject
{
    private BusinessObject(string property)
    {
    }

    public class Factory
    {
        public static BusinessObject CreateBusinessObject(string property)
        {
            return new BusinessObject(property);
        }
    }
}

यह काम करता है क्योंकि नेस्टेड प्रकारों के पास उनके संलग्न प्रकारों के निजी सदस्यों तक पहुंच होती है। मुझे पता है कि यह थोड़ा प्रतिबंधात्मक है, लेकिन उम्मीद है कि यह मदद करेगा ...


मैंने इसके बारे में सोचा था, लेकिन यह प्रभावी रूप से इन चेक को व्यावसायिक वस्तु में ले जाता है, जिससे मैं बचने की कोशिश कर रहा हूं।
यूजर

@ so-tester: आप अभी भी BusinessObject प्रकार के बजाय कारखाने में चेक रख सकते हैं।
जॉन स्केट

3
@JonSkeet मुझे पता है कि यह प्रश्न वास्तव में पुराना है, लेकिन मुझे इस बात की उत्सुकता है कि CreateBusinessObjectएक नेस्टेड Factoryक्लास के अंदर विधि को रखने का क्या फायदा है, बजाय इसके कि स्थैतिक विधि सीधे BusinessObjectवर्ग की एक विधि हो ... क्या आप अपने को याद कर सकते हैं ऐसा करने के लिए प्रेरणा?
केली नरो सिप

3
@KileyNaro: ठीक है, कि सवाल क्या पूछ रहा था :) यह जरूरी नहीं कि कई फायदे प्रदान करता है, लेकिन यह सवाल का जवाब देता है ... कई बार ऐसा हो सकता है जब यह उपयोगी है - बिल्डर पैटर्न को ध्यान में रखता है। (उस स्थिति में बिल्डर नेस्टेड क्लास होगा, और इसके पास एक इंस्टेंस विधि होगी जिसे कहा जाता है Build।)
जॉन स्कीट

53

या, यदि आप वास्तव में फैंसी, इनवर्ट कंट्रोल पर जाना चाहते हैं: तो क्या क्लास फैक्ट्री लौटा सकती है, और एक डेलीगेट के साथ फैक्ट्री को इंस्ट्रूमेंट करें जो क्लास क्रिएट कर सके।

public class BusinessObject
{
  public static BusinessObjectFactory GetFactory()
  {
    return new BusinessObjectFactory (p => new BusinessObject (p));
  }

  private BusinessObject(string property)
  {
  }
}

public class BusinessObjectFactory
{
  private Func<string, BusinessObject> _ctorCaller;

  public BusinessObjectFactory (Func<string, BusinessObject> ctorCaller)
  {
    _ctorCaller = ctorCaller;
  }

  public BusinessObject CreateBusinessObject(string myProperty)
  {
    if (...)
      return _ctorCaller (myProperty);
    else
      return null;
  }
}

:)


कोड का बहुत अच्छा टुकड़ा। ऑब्जेक्ट निर्माण तर्क एक अलग वर्ग में है और ऑब्जेक्ट केवल कारखाने का उपयोग करके बनाया जा सकता है।
निकोलाई सैमटेलजेड 15

ठंडा। क्या कोई ऐसा तरीका है जिससे आप BusinessObjectFactory के स्थैतिक BusinessObject.GetFactory के निर्माण को सीमित कर सकते हैं?
फेलिक्स कील

1
इस उलटा का फायदा क्या है?
yatskovsky

1
@yatskovsky यह सुनिश्चित करने का एक तरीका है कि वस्तु को केवल एक नियंत्रित फैशन में त्वरित किया जा सकता है, जबकि अभी भी एक समर्पित वर्ग में सृजन तर्क को सक्षम करने में सक्षम है।
फेबियन शिमिड

15

आप अपने MyBusinessObjectClass वर्ग पर आंतरिक निर्माण कर सकते हैं, और इसे और कारखाने को अपनी विधानसभा में स्थानांतरित कर सकते हैं। अब केवल कारखाने को कक्षा का एक उदाहरण बनाने में सक्षम होना चाहिए।


7

जॉन ने जो सुझाव दिया उसके अलावा, आप कारखाने की विधि (चेक सहित) पहली जगह में BusinessObject का एक स्थिर तरीका हो सकते हैं। फिर, कंस्ट्रक्टर को निजी रखें, और बाकी सभी को स्थिर विधि का उपयोग करने के लिए मजबूर किया जाएगा।

public class BusinessObject
{
  public static Create (string myProperty)
  {
    if (...)
      return new BusinessObject (myProperty);
    else
      return null;
  }
}

लेकिन असली सवाल यह है - आपको इसकी आवश्यकता क्यों है? क्या कारखाने या कारखाने के तरीके को कक्षा में स्थानांतरित करना स्वीकार्य है?


यह शायद ही एक आवश्यकता है। मैं सिर्फ व्यावसायिक वस्तु और तर्क को अलग करना चाहता हूं। जिस तरह इन चेकों को पेजों के कोड-बैक में रखना अनुचित है, वैसे ही इन चेकों को वस्तुओं में रखना मेरे लिए अनुचित है। ठीक है, शायद बुनियादी सत्यापन, लेकिन वास्तव में व्यावसायिक नियम नहीं।
यूजर

यदि आप केवल सुविधा की समीक्षा के लिए तर्क और एक वर्ग की संरचना को अलग करना चाहते हैं, तो आप हमेशा एक आंशिक वर्ग का उपयोग कर सकते हैं और दोनों को अलग-अलग फ़ाइलों में ...
Grx70

7

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

आपकी कक्षाओं के लिए इंटरफ़ेस:

public interface FactoryObject
{
    FactoryObject Instantiate();
}

आपकी कक्षा:

public class YourClass : FactoryObject
{
    static YourClass()
    {
        Factory.RegisterType(new YourClass());
    }

    private YourClass() {}

    FactoryObject FactoryObject.Instantiate()
    {
        return new YourClass();
    }
}

और, अंत में, कारखाना:

public static class Factory
{
    private static List<FactoryObject> knownObjects = new List<FactoryObject>();

    public static void RegisterType(FactoryObject obj)
    {
        knownObjects.Add(obj);
    }

    public static T Instantiate<T>() where T : FactoryObject
    {
        var knownObject = knownObjects.Where(x => x.GetType() == typeof(T));
        return (T)knownObject.Instantiate();
    }
}

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


4

फिर भी एक और (हल्का) विकल्प BusinessObject क्लास में एक स्टेटिक फ़ैक्टरी विधि बनाना और कंस्ट्रक्टर को निजी रखना है।

public class BusinessObject
{
    public static BusinessObject NewBusinessObject(string property)
    {
        return new BusinessObject();
    }

    private BusinessObject()
    {
    }
}

2

इसलिए, ऐसा लगता है कि जो मैं चाहता हूं वह "शुद्ध" तरीके से नहीं किया जा सकता है। यह हमेशा तर्क वर्ग के लिए "कॉल बैक" का कुछ प्रकार है।

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

public MyBusinessObjectClass
{
    public string MyProperty { get; private set; }

    private MyBusinessObjectClass (string myProperty)
    {
        MyProperty  = myProperty;
    }

    pubilc static MyBusinessObjectClass CreateInstance (string myProperty)
    {
        if (MyBusinessLogicClass.ValidateBusinessObject (myProperty)) return new MyBusinessObjectClass (myProperty);

        return null;
    }
}

public MyBusinessLogicClass
{
    public static bool ValidateBusinessObject (string myProperty)
    {
        // Perform some check on myProperty

        return CheckResult;
    }
}

इस तरह, व्यावसायिक वस्तु प्रत्यक्ष रूप से सृजनात्मक नहीं है और व्यावसायिक तर्क में सार्वजनिक जांच विधि कोई नुकसान नहीं करेगी।


2

इंटरफेस और कार्यान्वयन के बीच अच्छे अलगाव के मामले में
संरक्षित-कंस्ट्रक्टर-पब्लिक-इनिशियलाइज़र पैटर्न बहुत साफ समाधान की अनुमति देता है।

एक व्यावसायिक वस्तु दी:

public interface IBusinessObject { }

class BusinessObject : IBusinessObject
{
    public static IBusinessObject New() 
    {
        return new BusinessObject();
    }

    protected BusinessObject() 
    { ... }
}

और एक व्यापार कारखाना:

public interface IBusinessFactory { }

class BusinessFactory : IBusinessFactory
{
    public static IBusinessFactory New() 
    {
        return new BusinessFactory();
    }

    protected BusinessFactory() 
    { ... }
}

BusinessObject.New()इनिशलाइज़र में निम्नलिखित परिवर्तन समाधान देता है:

class BusinessObject : IBusinessObject
{
    public static IBusinessObject New(BusinessFactory factory) 
    { ... }

    ...
}

BusinessObject.New()इनिशियलाइज़र को कॉल करने के लिए कंक्रीट व्यवसाय कारखाने के संदर्भ की आवश्यकता होती है । लेकिन केवल एक ही जिसके पास आवश्यक संदर्भ है, वह स्वयं व्यवसाय का कारखाना है।

हमें वह मिला जो हम चाहते थे: केवल वही जो बना सकता BusinessObjectहै BusinessFactory


तो आप यह सुनिश्चित करते हैं कि ऑब्जेक्ट के एकमात्र काम करने वाले सार्वजनिक निर्माता को एक फैक्ट्री की आवश्यकता होती है, और उस फैक्ट्री पैरामीटर की आवश्यकता केवल फैक्ट्री के स्टैटिक मेथड को बताकर तत्काल की जा सकती है? एक काम कर रहे समाधान की तरह लगता है, लेकिन मुझे लगता है कि public static IBusinessObject New(BusinessFactory factory) अगर किसी और कोड को बनाए रखता है, तो स्निपेट जैसे कई भौहें उठाएंगे।
फ्लैटर

@ फैटल सहमत। मैं पैरामीटर नाम factoryको बदल दूंगा asFriend। मेरे कोड बेस में तब यह दिखाया गया थाpublic static IBusinessObject New(BusinessFactory asFriend)
रेवेन बेस

मुझे यह बिल्कुल नहीं मिलता। यह कैसे काम करता है? कारखाना IBusinessObject के नए उदाहरण नहीं बना सकता है और न ही ऐसा करने का कोई इरादा (तरीके) है ...?
लैप्स

2
    public class HandlerFactory: Handler
    {
        public IHandler GetHandler()
        {
            return base.CreateMe();
        }
    }

    public interface IHandler
    {
        void DoWork();
    }

    public class Handler : IHandler
    {
        public void DoWork()
        {
            Console.WriteLine("hander doing work");
        }

        protected IHandler CreateMe()
        {
            return new Handler();
        }

        protected Handler(){}
    }

    public static void Main(string[] args)
    {
        // Handler handler = new Handler();         - this will error out!
        var factory = new HandlerFactory();
        var handler = factory.GetHandler();

        handler.DoWork();           // this works!
    }

कृपया मेरे दृष्टिकोण का प्रयास करें, 'फैक्टरी' हैंडलर का कंटेनर है, और केवल यह खुद के लिए एक उदाहरण बना सकता है। कुछ संशोधन के साथ, यह आपकी आवश्यकताओं के अनुरूप हो सकता है।
लिन

1
आपके उदाहरण में, निम्नलिखित संभव नहीं होगा (जो समझ में नहीं आएगा) ?: factory.DoWork ();
15

1

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

public class Person
{
  internal Person()
  {
  }
}

public class PersonFactory
{
  public Person Create()
  {
    return new Person();
  }  
}

हालाँकि, मुझे आपके दृष्टिकोण पर सवाल उठाना चाहिए :-)

मुझे लगता है कि यदि आप चाहते हैं कि आपका व्यक्ति वर्ग निर्माण पर मान्य हो तो आपको कोड को निर्माणकर्ता में रखना होगा।

public class Person
{
  public Person(string firstName, string lastName)
  {
    FirstName = firstName;
    LastName = lastName;
    Validate();
  }
}

1

यह समाधान पर आधारित है munificents निर्माता में एक टोकन का उपयोग करने का विचार है। इस उत्तर में किया गया सुनिश्चित करें कि केवल कारखाने द्वारा बनाई गई वस्तु (C #)

  public class BusinessObject
    {
        public BusinessObject(object instantiator)
        {
            if (instantiator.GetType() != typeof(Factory))
                throw new ArgumentException("Instantiator class must be Factory");
        }

    }

    public class Factory
    {
        public BusinessObject CreateBusinessObject()
        {
            return new BusinessObject(this);
        }
    }

1

विभिन्न ट्रेडऑफ के साथ कई दृष्टिकोणों का उल्लेख किया गया है।

  • निजी रूप से निर्मित वर्ग में कारखाने के वर्ग को घोंसला बनाना कारखाने को केवल 1 वर्ग बनाने की अनुमति देता है। उस बिंदु पर आप एक Createविधि और एक निजी ctor के साथ बेहतर हैं ।
  • वंशानुक्रम और संरक्षित ctor का उपयोग करना एक ही मुद्दा है।

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

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

== ChemicalFactory.cs ==
partial class ChemicalFactory {
    private  ChemicalFactory() {}

    public interface IChemical {
        int AtomicNumber { get; }
    }

    public static IChemical CreateOxygen() {
        return new Oxygen();
    }
}


== Oxygen.cs ==
partial class ChemicalFactory {
    private class Oxygen : IChemical {
        public Oxygen() {
            AtomicNumber = 8;
        }
        public int AtomicNumber { get; }
    }
}



== Program.cs ==
class Program {
    static void Main(string[] args) {
        var ox = ChemicalFactory.CreateOxygen();
        Console.WriteLine(ox.AtomicNumber);
    }
}

0

मुझे समझ नहीं आता कि आप "व्यावसायिक तर्क" को "व्यावसायिक वस्तु" से अलग क्यों करना चाहते हैं। यह ऑब्जेक्ट ओरिएंटेशन की विकृति की तरह लगता है, और आप उस दृष्टिकोण को ले कर अपने आप को गांठ में बांध लेंगे।


मैं इस भेद को नहीं समझता। क्या कोई समझा सकता है कि ऐसा क्यों किया जा रहा है, और व्यावसायिक वस्तु में क्या कोड होगा?
pipTheGeek

यह सिर्फ एक दृष्टिकोण है जिसका उपयोग किया जा सकता है। मैं चाहता हूं कि व्यावसायिक वस्तु मुख्य रूप से डेटा संरचनाएं हों, लेकिन पढ़ने / लिखने के लिए खुले सभी क्षेत्रों के साथ नहीं। लेकिन सवाल वास्तव में केवल एक फैक्ट्री पद्धति की मदद से किसी वस्तु को तत्काल करने में सक्षम था और सीधे नहीं।
यूजर

@ जिम: मैं व्यक्तिगत रूप से आपकी बात से सहमत हूं, लेकिन पेशेवर रूप से, यह लगातार किया जाता है। मेरी वर्तमान परियोजना एक webservice है जो HTML स्ट्रिंग लेती है, इसे कुछ पूर्व निर्धारित नियमों के अनुसार साफ करती है, फिर साफ किए गए स्ट्रिंग को वापस करती है। मुझे अपने स्वयं के कोड की 7 परतों से गुजरने की आवश्यकता है "क्योंकि हमारी सभी परियोजनाएं एक ही प्रोजेक्ट टेम्पलेट से निर्मित होनी चाहिए"। यह इस कारण से है कि SO पर इन प्रश्नों को पूछने वाले अधिकांश लोगों को अपने कोड के संपूर्ण प्रवाह को बदलने की स्वतंत्रता नहीं मिलती है।
फ्लैटर

0

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

एक विकल्प के लिए एक स्थिर निर्माणकर्ता है जो एक कारखाने को आईओसी कंटेनर की तरह कुछ के साथ पंजीकृत करता है।


0

यहाँ "सिर्फ इसलिए कि आप का मतलब यह नहीं होना चाहिए कि आप" के नस में एक और समाधान है ...

यह व्यावसायिक वस्तु निर्माता को निजी रखने और कारखाने के तर्क को किसी अन्य वर्ग में रखने की आवश्यकताओं को पूरा करता है। इसके बाद यह थोड़ा स्केच हो जाता है।

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

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

क्या रोका नहीं है ग्राहक कोड भी है को व्यावसायिक ऑब्जेक्ट क्लास से प्राप्त करने और संरक्षित (लेकिन अनवीक्षित) स्थिर निर्माण विधि को कॉल करने से । या इससे भी बदतर, संरक्षित डिफॉल्ट कंस्ट्रक्टर को कॉल करके हमें पहले स्थान पर संकलन करने के लिए फ़ैक्टरी क्लास को जोड़ना था। (जो संयोग से किसी भी पैटर्न के साथ एक समस्या होने की संभावना है जो फैक्ट्री क्लास को व्यावसायिक ऑब्जेक्ट क्लास से अलग करता है।)

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

using System;

public class MyBusinessObjectClass
{
    public string MyProperty { get; private set; }

    private MyBusinessObjectClass(string myProperty)
    {
        MyProperty = myProperty;
    }

    // Need accesible default constructor, or else MyBusinessObjectFactory declaration will generate:
    // error CS0122: 'MyBusinessObjectClass.MyBusinessObjectClass(string)' is inaccessible due to its protection level
    protected MyBusinessObjectClass()
    {
    }

    protected static MyBusinessObjectClass Construct(string myProperty)
    {
        return new MyBusinessObjectClass(myProperty);
    }
}

public abstract class MyBusinessObjectFactory : MyBusinessObjectClass
{
    public static MyBusinessObjectClass CreateBusinessObject(string myProperty)
    {
        // Perform some check on myProperty

        if (true /* check is okay */)
            return Construct(myProperty);

        return null;
    }

    private MyBusinessObjectFactory()
    {
    }
}

0

इस समाधान पर कुछ विचार सुनने की सराहना करेंगे। केवल एक ही 'MyClassPrivilegeKey' बनाने में सक्षम है। और 'MyClass' को कंस्ट्रक्टर में इसकी आवश्यकता है। इस प्रकार कारखाने में निजी ठेकेदारों / "पंजीकरण" पर प्रतिबिंब से बचना।

public static class Runnable
{
    public static void Run()
    {
        MyClass myClass = MyClassPrivilegeKey.MyClassFactory.GetInstance();
    }
}

public abstract class MyClass
{
    public MyClass(MyClassPrivilegeKey key) { }
}

public class MyClassA : MyClass
{
    public MyClassA(MyClassPrivilegeKey key) : base(key) { }
}

public class MyClassB : MyClass
{
    public MyClassB(MyClassPrivilegeKey key) : base(key) { }
}


public class MyClassPrivilegeKey
{
    private MyClassPrivilegeKey()
    {
    }

    public static class MyClassFactory
    {
        private static MyClassPrivilegeKey key = new MyClassPrivilegeKey();

        public static MyClass GetInstance()
        {
            if (/* some things == */true)
            {
                return new MyClassA(key);
            }
            else
            {
                return new MyClassB(key);
            }
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.