अच्छा या बुरा अभ्यास? गेटटर में ऑब्जेक्ट्स को इनिशियलाइज़ करना


167

मुझे एक अजीब आदत है ऐसा लगता है ... मेरे सहकर्मी के अनुसार कम से कम। हम एक साथ एक छोटे से प्रोजेक्ट पर काम कर रहे हैं। जिस तरह से मैंने कक्षाएँ लिखी हैं (सरलीकृत उदाहरण):

[Serializable()]
public class Foo
{
    public Foo()
    { }

    private Bar _bar;

    public Bar Bar
    {
        get
        {
            if (_bar == null)
                _bar = new Bar();

            return _bar;
        }
        set { _bar = value; }
    }
}

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

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

क्या व्यक्तिगत प्राथमिकता के अलावा इस प्रथा के खिलाफ कोई आपत्ति है?

अद्यतन: मैंने इस प्रश्न के संबंध में कई अलग-अलग राय पर विचार किया है और मैं अपने स्वीकृत उत्तर के साथ खड़ा रहूंगा। हालांकि, मैं अब अवधारणा की बहुत बेहतर समझ में आ गया हूं और यह तय करने में सक्षम हूं कि इसका उपयोग कब करना है और कब नहीं।

विपक्ष:

  • थ्रेड सुरक्षा मुद्दों
  • जब मान पास हो तो "सेटर" अनुरोध न मानना
  • माइक्रो अनुकूलन
  • एक निर्माणकर्ता में अपवाद हैंडलिंग होनी चाहिए
  • कक्षा 'कोड में अशक्त के लिए जाँच करने की आवश्यकता है

पेशेवरों:

  • माइक्रो अनुकूलन
  • गुण कभी अशक्त नहीं लौटते
  • देरी या "भारी" वस्तुओं को लोड करने से बचें

अधिकांश विपक्ष मेरे वर्तमान पुस्तकालय पर लागू नहीं होते हैं, हालांकि मुझे यह देखने के लिए परीक्षण करना होगा कि क्या "सूक्ष्म-अनुकूलन" वास्तव में कुछ भी अनुकूलन कर रहे हैं।

आखिरी अपडेट:

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


14
यह आलसी-भार पैटर्न है, इसकी बिल्कुल आपको यहाँ एक अद्भुत लाभ नहीं दे रहा है लेकिन यह अभी भी एक अच्छी बात है।
मैकिनरियस

28
आलसी तात्कालिकता यह समझ में आता है कि क्या आपके पास एक औसत दर्जे का प्रदर्शन प्रभाव है, या यदि उन सदस्यों का उपयोग शायद ही कभी किया जाता है और स्मृति की अत्यधिक मात्रा में खपत होती है, या यदि उन्हें त्वरित करने में लंबा समय लगता है और केवल मांग पर करना चाहते हैं। किसी भी दर पर, धागा सुरक्षा मुद्दों (आपका वर्तमान कोड नहीं है ) के लिए सुनिश्चित करें और प्रदान की गई आलसी <टी> वर्ग का उपयोग करने पर विचार करें ।
क्रिस सिनक्लेयर

10
मुझे लगता है कि यह सवाल codereview.stackexchange.com
एडुआर्डो ने

7
@PLB यह एक सिंगलटन पैटर्न नहीं है।
कॉलिन मैके

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

जवाबों:


170

आपके पास यहां क्या है - एक "भोलापन आरंभीकरण" का एक अनुभवहीन - कार्यान्वयन।

संक्षिप्त जवाब:

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

पृष्ठभूमि और स्पष्टीकरण:

कंक्रीट कार्यान्वयन:
आइए पहले अपने ठोस नमूने को देखें और मैं इसके कार्यान्वयन को भोला क्यों मानता हूं:

  1. यह प्रिंसिपल ऑफ़ लीस्ट सरप्राइज़ (POLS) का उल्लंघन करता है । जब कोई मान किसी संपत्ति को सौंपा जाता है, तो यह अपेक्षा की जाती है कि यह मान वापस कर दिया जाए। आपके कार्यान्वयन में यह मामला नहीं है null:

    foo.Bar = null;
    Assert.Null(foo.Bar); // This will fail
  2. यह काफी कुछ थ्रेडिंग मुद्दों का परिचय देता है: foo.Barअलग-अलग थ्रेड के दो कॉलर्स संभावित रूप से दो अलग-अलग उदाहरण प्राप्त कर सकते हैं Barऔर उनमें से एक उदाहरण के कनेक्शन के बिना होगा Foo। उस Barउदाहरण में किए गए कोई भी परिवर्तन चुपचाप खो जाते हैं।
    यह POLS के उल्लंघन का एक और मामला है। जब किसी संपत्ति का केवल संग्रहीत मूल्य एक्सेस किया जाता है तो यह थ्रेड-सुरक्षित होने की उम्मीद है। हालांकि आप यह तर्क दे सकते हैं कि वर्ग केवल थ्रेड-सुरक्षित नहीं है - जिसमें आपकी संपत्ति का प्राप्तकर्ता भी शामिल है - आपको इसे ठीक से दस्तावेज़ करना होगा क्योंकि यह सामान्य मामला नहीं है। इसके अलावा इस मुद्दे की शुरूआत अनावश्यक है क्योंकि हम जल्द ही देखेंगे।

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

हालांकि, ऐसी संपत्तियों में आम तौर पर कोई समझौता नहीं होता है, जो ऊपर बताए गए पहले मुद्दे से छुटकारा दिलाता है।
इसके अलावा, एक थ्रेड-सुरक्षित कार्यान्वयन का उपयोग किया जाएगा - जैसे Lazy<T>- दूसरे मुद्दे से बचने के लिए।

आलसी संपत्ति के कार्यान्वयन में इन दो बिंदुओं पर विचार करते समय, निम्नलिखित बिंदु इस पैटर्न की सामान्य समस्याएं हैं:

  1. ऑब्जेक्ट का निर्माण असफल हो सकता है, जिसके परिणामस्वरूप प्रॉपर्टी गेट्टर से अपवाद हो सकता है। यह अभी तक POLS का एक और उल्लंघन है और इसलिए इसे टाला जाना चाहिए। यहां तक ​​कि "डिजाइन गाइडलाइन्स फॉर डेवलपिंग क्लास लाइब्रेरीज़" में संपत्तियों पर अनुभाग स्पष्ट रूप से बताता है कि संपत्ति पाने वालों को अपवाद नहीं फेंकना चाहिए:

    संपत्ति पाने वालों से अपवाद को फेंकने से बचें।

    संपत्ति पाने वालों को बिना किसी पूर्व शर्त के सरल ऑपरेशन करना चाहिए। यदि कोई गेटर अपवाद छोड़ सकता है, तो संपत्ति को एक विधि के रूप में नया स्वरूप देने पर विचार करें।

  2. कंपाइलर द्वारा स्वचालित अनुकूलन को चोट लगी है, अर्थात् इनलाइनिंग और शाखा भविष्यवाणी। कृपया विस्तृत विवरण के लिए बिल के उत्तर देखें ।

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

इस पैटर्न का अपना स्थान है, लेकिन कक्षाओं को लागू करते समय यह एक सामान्य सर्वोत्तम अभ्यास नहीं है। ऊपर बताए गए कारणों की वजह से इसका बिना शर्त इस्तेमाल नहीं किया जाना चाहिए


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

  1. क्रमांकन:
    एरिकजे एक टिप्पणी में कहता है:

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

    इस तर्क के साथ कई समस्याएं हैं:

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

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

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

4
@ जॉनहिल्मसे: यह आपकी वास्तुकला की समस्या है। आपको अपनी कक्षाओं को इस तरह से रिफ्लेक्टर करना चाहिए कि वे छोटे और अधिक केंद्रित हों। 5 अलग-अलग चीजों / कार्यों के लिए एक वर्ग न बनाएं। इसके बजाय 5 कक्षाएं बनाएं।
डैनियल हिलगर्थ

26
@ जॉनहिल्मसे शायद इसे समय से पहले अनुकूलन का मामला मानते हैं। जब तक आपके पास एक मापा प्रदर्शन / मेमोरी टोंटी नहीं है, मैं इसके खिलाफ सिफारिश करूंगा क्योंकि यह जटिलता बढ़ाता है और थ्रेडिंग मुद्दों का परिचय देता है।
क्रिस सिंक्लेयर

2
+1, यह 95% वर्गों के लिए एक अच्छा डिज़ाइन विकल्प नहीं है। आलसी आरंभीकरण के अपने नियम हैं, लेकिन सभी गुणों के लिए इसे सामान्यीकृत नहीं किया जाना चाहिए। यह जटिलता, कोड को पढ़ने में कठिनाई, धागा सुरक्षा मुद्दों को जोड़ता है ... 99% मामलों में कोई बोधगम्य अनुकूलन के लिए नहीं। साथ ही, समाधानयोगी ने एक टिप्पणी के रूप में कहा, ओपी का कोड छोटी गाड़ी है, जो यह साबित करता है कि इस पैटर्न को लागू करने के लिए तुच्छ नहीं है और इसे तब तक टाला जाना चाहिए जब तक कि आलसी आरंभीकरण की वास्तव में आवश्यकता न हो।
ken2k

2
@DanielHilgarth बिना शर्त के इस पैटर्न का उपयोग करने के साथ गलत लिखने के लिए धन्यवाद। अच्छा काम!
एलेक्स

1
@DanielHilgarth खैर हाँ और नहीं। उल्लंघन यहाँ मुद्दा है इसलिए हाँ। लेकिन यह भी 'नहीं' क्योंकि POLS कड़ाई से सिद्धांत है कि आप शायद कोड से आश्चर्यचकित नहीं होंगे । यदि फू आपके कार्यक्रम के बाहर उजागर नहीं किया गया था, तो यह एक जोखिम है जिसे आप ले सकते हैं या नहीं। इस मामले में, मैं लगभग गारंटी दे सकता हूं कि आप अंततः आश्चर्यचकित होंगे , क्योंकि आप उस तरीके को नियंत्रित नहीं करते हैं जिस तरह से संपत्तियां पहुंचती हैं। जोखिम सिर्फ एक बग बन गया, और nullमामले के बारे में आपका तर्क बहुत मजबूत हो गया। :-)
atlaste

49

यह एक अच्छा डिजाइन विकल्प है। लाइब्रेरी कोड या कोर कक्षाओं के लिए दृढ़ता से अनुशंसा की जाती है।

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

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

दूसरा, संसाधन केवल जरूरत पड़ने पर बनाया जाता है।

तीसरा, आप किसी ऐसी वस्तु को इकट्ठा करने वाले कचरे से बचते हैं जिसका उपयोग नहीं किया गया था।

अंत में, प्रारंभिक अपवाद अपवादों को संभालना आसान है जो संपत्ति में हो सकते हैं फिर अपवाद जो कक्षा स्तर के चर या निर्माणकर्ता के प्रारंभ के दौरान होते हैं।

इस नियम के अपवाद हैं।

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

Http://msdn.microsoft.com/en-US/library/vstudio/ms229042.aspx पर कक्षा पुस्तकालयों के विकास के लिए डिजाइन दिशानिर्देश

के बारे में Lazy<T>

जेनेरिक Lazy<T>क्लास ठीक उसी तरह से बनाई गई थी जैसा कि पोस्टर चाहता है, http://msdn.microsoft.com/en-us/library/dd997286(v=vs.100).aspx पर आलसी इनिशियलाइज़ेशन देखें । यदि आपके पास .NET के पुराने संस्करण हैं, तो आपको प्रश्न में चित्रित कोड पैटर्न का उपयोग करना होगा। यह कोड पैटर्न इतना आम हो गया है कि Microsoft ने नवीनतम .NET पुस्तकालयों में एक वर्ग को शामिल करने के लिए फिट देखा ताकि पैटर्न को लागू करना आसान हो सके। इसके अलावा, यदि आपके कार्यान्वयन को थ्रेड सुरक्षा की आवश्यकता है, तो आपको इसे जोड़ना होगा।

आदिम डेटा प्रकार और सरल वर्ग

Obvioulsy, आप आदिम डेटा प्रकार या सरल वर्ग उपयोग के लिए आलसी-आरंभ का उपयोग नहीं करने जा रहे हैं List<string>

लेज़ी के बारे में टिप्पणी करने से पहले

Lazy<T> .NET 4.0 में पेश किया गया था, इसलिए कृपया इस वर्ग के संबंध में एक और टिप्पणी न करें।

माइक्रो-ऑप्टिमाइज़ेशन के बारे में टिप्पणी करने से पहले

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

उपयोगकर्ता-इंटरफेस के बारे में

आप उन कक्षाओं के लिए आलसी इनिशियलाइज़ेशन का उपयोग नहीं करने जा रहे हैं जो सीधे उपयोगकर्ता-इंटरफ़ेस द्वारा उपयोग किए जाते हैं। पिछले हफ्ते मैंने कॉम्बो-बॉक्स के लिए एक दृश्य-मॉडल में उपयोग किए गए आठ संग्रहों के आलसी लोडिंग को हटाने के एक दिन का बेहतर हिस्सा बिताया। मेरे पास एक LookupManagerआलसी लोडिंग और किसी भी उपयोगकर्ता-इंटरफ़ेस तत्व द्वारा आवश्यक संग्रह के कैशिंग को संभालता है।

"Setters"

मैंने कभी किसी आलसी भरी संपत्ति के लिए सेट-प्रॉपर्टी ("सेटलर्स") का उपयोग नहीं किया है। इसलिए, आप कभी भी अनुमति नहीं देंगे foo.Bar = null;। यदि आपको सेट करने की आवश्यकता है Barतो मैं एक विधि बनाऊंगा जिसे SetBar(Bar value)आलसी-आरंभीकरण का उपयोग नहीं करना चाहिए

संग्रह

क्लास कलेक्शन प्रॉपर्टीज को हमेशा घोषित किए जाने के बाद शुरू किया जाता है क्योंकि उन्हें कभी भी अशक्त नहीं होना चाहिए।

जटिल कक्षाएं

मुझे इसे अलग तरह से दोहराना है, आप जटिल कक्षाओं के लिए आलसी-आरंभीकरण का उपयोग करते हैं। जो आमतौर पर, खराब तरीके से डिजाइन की गई कक्षाएं हैं।

अंततः

मैंने सभी वर्गों या सभी मामलों में ऐसा करने के लिए कभी नहीं कहा। यह एक बुरी आदत है।


6
यदि आप foo.Bar को अलग-अलग थ्रेड्स में कई बार बिना किसी हस्तक्षेप मूल्य सेटिंग के कॉल कर सकते हैं, लेकिन अलग-अलग मान प्राप्त करते हैं, तो आपके पास एक घटिया गरीब वर्ग है।
रेयान

25
मुझे लगता है कि यह कई विचारों के बिना अंगूठे का एक बुरा नियम है। जब तक बार एक पता संसाधन हॉग नहीं है, यह एक अनावश्यक माइक्रो ऑप्टिमाइज़ेशन है। और इस मामले में कि बार संसाधन गहन है, थ्रेड सुरक्षित है आलसी <T> .net में निर्मित।
एंड्रयू हैनॉन

10
"प्रारंभिक अपवाद अपवाद को संभालना आसान है जो संपत्ति में हो सकता है, फिर अपवाद जो वर्ग स्तर के चर या निर्माता के प्रारंभ के दौरान होता है।" - ठीक है, यह मूर्खतापूर्ण है। यदि किसी कारण से किसी वस्तु को आरंभ नहीं किया जा सकता है, तो मैं ASAP जानना चाहता हूं। निर्माण होने पर तुरंत। आलसी आरंभीकरण का उपयोग करने के लिए अच्छे तर्क दिए जा रहे हैं, लेकिन मुझे नहीं लगता कि इसका व्यापक रूप से उपयोग करना एक अच्छा विचार है ।
20-13 को मिली

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

4
बहुत सारे संकेतक हैं जो आप गलत उत्तर (और गलत प्रोग्रामिंग निर्णय) चुन रहे हैं। आपकी सूची में पेशेवरों की तुलना में अधिक विपक्ष है। आपके पास इसके मुकाबले ज्यादा लोग हैं। इस साइट के अधिक अनुभवी सदस्य (@BillK और @DanielHilgarth) जो इस प्रश्न में तैनात हैं, इसके खिलाफ हैं। आपके सहकर्मी ने पहले ही बता दिया कि यह गलत है। सच में, यह गलत है! यदि मैं अपनी टीम के डेवलपर्स में से एक (मैं एक टीम लीडर हूं) ऐसा कर रहा हूं, तो वह 5 मिनट का समय लेगा और फिर व्याख्यान दिया जाएगा कि उसे ऐसा क्यों नहीं करना चाहिए।
एलेक्स

17

क्या आप इस तरह के पैटर्न को लागू करने पर विचार करते हैं Lazy<T>?

आलसी-भारित वस्तुओं के आसान निर्माण के अलावा, आपको ऑब्जेक्ट को आरंभीकृत करते समय थ्रेड सुरक्षा मिलती है:

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


धन्यवाद, मैं इसे अब समझ गया हूं और अब मैं निश्चित रूप Lazy<T>से देखूंगा, और जिस तरह से मैं हमेशा करता था, उसका उपयोग करने से बचना चाहिए।
जॉन विलेमसे 14

1
आपको मैजिक थ्रेड सुरक्षा नहीं मिलती है ... आपको अभी भी इसके बारे में सोचना है। MSDN से:Making the Lazy<T> object thread safe does not protect the lazily initialized object. If multiple threads can access the lazily initialized object, you must make its properties and methods safe for multithreaded access.
एरिक जे।

@EricJ। कोर्स के पाठ्यक्रम की। ऑब्जेक्ट को इनिशियलाइज़ करते समय आपको केवल थ्रेड-सेफ्टी मिलती है, लेकिन बाद में आपको किसी अन्य ऑब्जेक्ट के रूप में सिंक्रोनाइज़ेशन से निपटना पड़ता है।
मैटिस फिडेमाइजर

9

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

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


धन्यवाद! यह समझ आता है।
जॉन विलेमसे

9

नकारात्मक पक्ष जो मैं देख सकता हूं कि यदि आप पूछना चाहते हैं कि क्या बार्स अशक्त है, तो यह कभी नहीं होगा, और आप वहां सूची बना रहे होंगे।


मुझे नहीं लगता कि यह एक नकारात्मक पहलू है।
पीटर पोर्फी

क्यों यह एक नकारात्मक पहलू है? बस अशक्त के बजाय किसी के साथ की जाँच करें। if (! Foo.Bars.Any ())
s.meijer

6
@PeterPorfy: यह उल्लंघन करता है, परास्नातक । आप डालते nullहैं, लेकिन इसे वापस नहीं पाते हैं। आम तौर पर, आप मान लेते हैं कि आपको एक ही मूल्य वापस मिलता है जो आप एक संपत्ति में डालते हैं।
डैनियल हिल्गरथ

@DanielHilgarth फिर से धन्यवाद। यह एक बहुत ही मान्य तर्क है जिस पर मैंने पहले विचार नहीं किया था।
जॉन विलेमसे

6
@ इमिसिको: यह एक बनावटी अवधारणा नहीं है। उसी तरह से कि सामने वाले दरवाजे के बगल में एक बटन दबाने से एक घंटी बजने की उम्मीद है, जो चीजें गुणों की तरह दिखती हैं उनसे गुणों की तरह व्यवहार करने की उम्मीद की जाती है। अपने पैरों के नीचे एक जाल दरवाजा खोलना एक आश्चर्यजनक व्यवहार है, खासकर अगर बटन को इस तरह से लेबल नहीं किया गया है।
ब्रायन बोएचर 19

8

आलसी तात्कालिकता / आरंभीकरण एक पूरी तरह से व्यवहार्य पैटर्न है। हालांकि, ध्यान रखें कि आपके एपीआई के एक सामान्य नियम के रूप में उपभोक्ताओं को गेटवे की उम्मीद नहीं है और अंतिम उपयोगकर्ता पीओवी (या विफल होने) से समय लेने योग्य है।


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

8

मैं सिर्फ डैनियल के जवाब पर एक टिप्पणी करने जा रहा था, लेकिन मुझे नहीं लगता कि यह बहुत दूर तक जाता है।

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

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

सुरक्षित श्रेणी
{
    स्ट्रिंग नाम = "";
    पूर्णांक आयु = 0;

    सार्वजनिक शून्य सेटनाम (स्ट्रिंग नया नाम)
    {
        मुखर (नया नाम! = अशक्त)
        नाम = NewName;
    } // उम्र के लिए इस पैटर्न का पालन करें
    ...
    सार्वजनिक स्ट्रिंग toString () {
        स्ट्रिंग s = "सुरक्षित वर्ग का नाम है:" + नाम + "और आयु:" + आयु
    }
}

आपके पैटर्न के साथ, स्ट्रीडिंग विधि इस तरह दिखाई देगी:

    अगर (नाम == अशक्त)
        नया अवैध फेंकना अपवाद ("SafeClass एक अवैध स्थिति में मिला! नाम शून्य है")
    अगर (उम्र == अशक्त)
        नई अवैध फेंकना अपवाद ("SafeClass एक अवैध स्थिति में मिला है! उम्र शून्य है")

    सार्वजनिक स्ट्रिंग toString () {
        स्ट्रिंग s = "सुरक्षित वर्ग का नाम है:" + नाम + "और आयु:" + आयु
    }

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

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

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

चोकर भविष्यवाणी की समस्या के उदाहरण के लिए (जिसे आप बार-बार उकसा रहे हैं, सिर्फ एक बार नोस्ट करें), इस भयानक प्रश्न का पहला उत्तर देखें: एक अनारक्षित सरणी की तुलना में सॉर्ट किए गए सरणी को संसाधित करना अधिक तेज़ क्यों है?


आपके सहयोग के लिए धन्यवाद। मेरे मामले में, कक्षाओं में से किसी के पास कोई भी तरीका नहीं है, जो अशक्त के लिए जाँचने की आवश्यकता हो सकती है, इसलिए यह कोई समस्या नहीं है। मैं आपकी अन्य आपत्तियों को ध्यान में रखूंगा।
जॉन विलेमसे

मैं वास्तव में यह नहीं समझता। तात्पर्य यह है कि आप अपने सदस्यों को उन कक्षाओं में उपयोग नहीं कर रहे हैं जहाँ वे संग्रहीत हैं - कि आप कक्षाओं को डेटा संरचनाओं के रूप में उपयोग कर रहे हैं। अगर ऐसा है तो आप javaworld.com/javaworld/jw-01-2004/jw-0102-toolbox.html को पढ़ना चाहते हैं, जिसमें इस बात का अच्छा विवरण है कि बाहरी स्थिति से छेड़छाड़ करके अपने कोड को कैसे बेहतर बनाया जा सकता है। यदि आप उन्हें आंतरिक रूप से जोड़-तोड़ कर रहे हैं, तो आप बार-बार सब कुछ बिना जांचे-परखे कैसे करते हैं?
बिल K

इस जवाब के कुछ हिस्से अच्छे हैं, लेकिन कुछ हिस्सों में विरोधाभास है। आम तौर पर इस पैटर्न का उपयोग करते समय, toString()कॉल करेगा getName(), nameसीधे उपयोग नहीं करेगा ।
इज़काता

@BillK हाँ, कक्षाएं एक विशाल डेटा संरचना हैं। सभी काम स्थिर कक्षाओं में किया जाता है। मैं लिंक पर लेख की जांच करूंगा। धन्यवाद!
जॉन विलेमसे

1
@izkata वास्तव में एक वर्ग के अंदर ऐसा प्रतीत होता है कि मौसम के अनुसार आप एक गेट्टर का उपयोग करते हैं या नहीं, अधिकांश जगहों पर मैंने सीधे सदस्य का उपयोग किया है। एक तरफ, यदि आप हमेशा एक गेटर का उपयोग कर रहे हैं यदि () विधि और भी अधिक हानिकारक है, क्योंकि शाखा पूर्वानुमान विफलता अधिक बार होगी और ब्रांचिंग की वजह से रनटर को समेटने में अधिक परेशानी होगी। हालांकि, यह सब कुछ जॉन के रहस्योद्घाटन के साथ है कि वे डेटा संरचना और स्थिर वर्ग हैं, यही वह चीज है जिसके साथ मैं बहुत चिंतित हूं।
बिल K

4

मुझे केवल दूसरों द्वारा किए गए कई अच्छे बिंदुओं में एक और बिंदु जोड़ना है ...

डिबगर विल ( डिफ़ॉल्ट रूप से ) कोड के माध्यम से कदम रखते समय गुणों का मूल्यांकन करता है, जो संभावित Barरूप से जितनी जल्दी हो सके तुरंत कोड को निष्पादित करके होगा। दूसरे शब्दों में, डीबगिंग का एक मात्र कार्य कार्यक्रम के निष्पादन को बदल रहा है।

यह एक समस्या हो सकती है या नहीं (साइड-इफेक्ट्स के आधार पर), लेकिन इसके बारे में पता होना चाहिए।


2

क्या आप सुनिश्चित हैं कि फू को तुरंत कुछ भी करना चाहिए?

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

यदि फिर भी फू का होने का उद्देश्य बार के उदाहरणों को बनाना है, तो मैं इसे आलसी करने के साथ कुछ भी गलत नहीं देखता हूं।


4
@BenjaminGruenbaum नहीं, वास्तव में नहीं। और सम्मान से, भले ही यह था, आप किस बिंदु पर बनाने की कोशिश कर रहे थे?
KaptajnKold
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.