क्या यह सिर्फ एक चर के दायरे को कम करने के लिए ब्लॉक बनाने के लिए समझ में आता है?


38

मैं जावा में एक कार्यक्रम लिख रहा हूं, जहां एक बिंदु पर मुझे अपने कीस्टोर के लिए एक पासवर्ड लोड करने की आवश्यकता है। बस मज़े के लिए, मैंने ऐसा करने से जावा में अपना पासवर्ड कम से कम रखने की कोशिश की:

//Some code
....

KeyManagerFactory keyManager = KeyManagerFactory.getInstance("SunX509");
Keystore keyStore = KeyStore.getInstance("JKS");

{
    char[] password = getPassword();
    keyStore.load(new FileInputStream(keyStoreLocation), password);
    keyManager.init(keyStore, password);
}

...
//Some more code

अब, मुझे पता है कि यह थोड़े गूंगा है। वहाँ अन्य चीजों का एक गुच्छा है जो मैं कर सकता था, उनमें से ज्यादातर वास्तव में बेहतर थे (मैं एक चर का उपयोग नहीं कर सकता था)।

हालाँकि, मैं उत्सुक था कि क्या कोई मामला है जहाँ ऐसा करना इतना गूंगा नहीं था। केवल एक चीज जो मैं सोच सकता हूं, वह यह है कि यदि आप आम चर नामों का पुन: उपयोग करना चाहते हैं count, या temp, लेकिन अच्छे नामकरण सम्मेलनों और छोटी विधियों से यह संभव नहीं लगता है जो उपयोगी होगा।

क्या कोई ऐसा मामला है जहां केवल वैरिएबल स्कोप को कम करने के लिए ब्लॉक का उपयोग करना समझ में आता है?


13
@ नागट .... क्या? मुझे यह भी पता नहीं है कि अपने प्रश्न को उस डूप लक्ष्य के समान कैसे संपादित किया जाए। इसके कारण आपको इन सवालों पर विश्वास करने का कौन सा हिस्सा मिला?
लॉर्ड फरक्वाड

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

4
ऐसे ही कुछ प्रश्न हैं जो C ++ के लिए यह पूछते हैं: क्या कोड के ब्लॉक बनाने के लिए यह बुरा अभ्यास है? और घुंघराले कोष्ठक के साथ संरचना कोड । हो सकता है कि उनमें से एक में इस प्रश्न का उत्तर हो, हालाँकि C ++ और Java इस संबंध में बहुत भिन्न हैं।
आमोन


4
@gnat वह सवाल भी क्यों खुला? यह उन चौड़ी चीजों में से एक है जिन्हें मैंने कभी देखा है। क्या यह एक विहित प्रश्न पर एक प्रयास है?
jpmc26

जवाबों:


34

सबसे पहले, अंतर्निहित यांत्रिकी से बात करना:

C ++ स्कोप में == आजीवन b / c डिस्ट्रक्टर्स को स्कोप से बाहर निकलने पर आमंत्रित किया जाता है। इसके अलावा, C / C ++ में एक महत्वपूर्ण अंतर हम स्थानीय वस्तुओं की घोषणा कर सकते हैं। C / C ++ के लिए रनटाइम में कंपाइलर आम तौर पर विधि के लिए एक स्टैक फ्रेम आवंटित करेगा, जिसकी आवश्यकता उतनी ही हो सकती है, जितनी अग्रिम में, प्रत्येक स्कोप में प्रवेश करने पर अधिक स्टैक स्पेस आवंटित करने के बजाय (जो चर घोषित करता है)। तो, संकलक ढहने या समतल कर रहा है।

C / C ++ कंपाइलर स्थानीय लोगों के लिए स्टैक स्टोरेज स्पेस का पुन: उपयोग कर सकता है जो उपयोग जीवनकाल में संघर्ष नहीं करता है (यह आमतौर पर स्कोप के बजाय इसे निर्धारित करने के लिए वास्तविक कोड के विश्लेषण का उपयोग करेगा, b / c जो स्कोप से अधिक सटीक है!)।

मैं C / C ++ b / c जावा के सिंटैक्स का उल्लेख करता हूं, यानी घुंघराले ब्रेसिज़ और स्कूपिंग, कम से कम उस परिवार से प्राप्त भाग में हैं। और यह भी क्योंकि C ++ प्रश्न टिप्पणियों में आया था।

इसके विपरीत, जावा में स्थानीय वस्तुओं का होना संभव नहीं है: सभी ऑब्जेक्ट्स हीप ऑब्जेक्ट्स हैं, और सभी लोकल / फॉर्मल या तो रेफरेंस वैरिएबल या आदिम प्रकार (btw, वही स्टेटिक्स के लिए सही है)।

इसके अलावा, जावा स्कोप और आजीवन में समान रूप से समानता नहीं है: स्कोप / इन स्कोप एक्सेसिबिलिटी और नाम संघर्षों के लिए जा रहा है एक ज्यादातर संकलन समय अवधारणा है; चर की सफाई के संबंध में स्कोप से बाहर निकलने पर जावा में वास्तव में कुछ भी नहीं होता है। जावा का कचरा संग्रह वस्तुओं के जीवनकाल को निर्धारित करता है (अंत बिंदु)।

इसके अलावा जावा के बायटेकोड मैकेनिज्म (जावा कंपाइलर का आउटपुट) सीमित दायरे के भीतर घोषित उपयोगकर्ता चर को विधि के शीर्ष स्तर तक बढ़ावा देता है, क्योंकि बाइटकोड स्तर पर कोई स्कोप फीचर नहीं है (यह C / C + + के समान है) ढेर)। सबसे अच्छा संकलक स्थानीय चर स्लॉट का पुन: उपयोग कर सकता है, लेकिन (सी / सी ++ के विपरीत) केवल अगर उनका प्रकार समान है।

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

प्रोग्रामर लाभ से बात करते हुए, मैं दूसरों के साथ सहमत होना चाहूंगा कि एक (निजी) विधि एक बेहतर निर्माण है, भले ही एक बार उपयोग किया जाए।

फिर भी, इसका नामकरण करने के लिए वास्तव में कुछ भी गलत नहीं है।

मैंने इसे दुर्लभ परिस्थितियों में किया है जब व्यक्तिगत तरीके बनाना एक बोझ है। उदाहरण के लिए, जब switchएक लूप के भीतर एक बड़े बयान का उपयोग करते हुए दुभाषिया लिखते हैं, तो मैं caseप्रत्येक मामले को एक अलग विधि बनाने के बजाय प्रत्येक मामले के लिए अलग-अलग मामलों को एक दूसरे से अलग रखने के लिए प्रत्येक के लिए एक अलग ब्लॉक का परिचय दे सकता हूं (प्रत्येक में से प्रत्येक) जो केवल एक बार आह्वान किया गया है)।

(ध्यान दें कि कोड के रूप में, अलग-अलग मामलों में "ब्रेक;" और "जारी है" तक पहुंच है, संलग्नक लूप के बारे में बयान, जबकि तरीकों के लिए इन नियंत्रण प्रवाह तक पहुंच प्राप्त करने के लिए वापसी करने वाले बूलियंस और सशर्त के कॉलर के उपयोग की आवश्यकता होगी। बयान।)


बहुत दिलचस्प जवाब (+1)! हालाँकि एक C ++ भाग का पूरक है। यदि पासवर्ड एक ब्लॉक में एक स्ट्रिंग है, तो स्ट्रिंग ऑब्जेक्ट वेरिएबल साइज पार्ट के लिए फ्री स्टोर पर कहीं जगह आवंटित करेगा। ब्लाक से बाहर निकलते समय, स्ट्रिंग नष्ट हो जाएगी, जिसके परिणामस्वरूप चर भाग का निपटान होगा। लेकिन जैसा कि यह स्टैक पर नहीं है, कुछ भी गारंटी नहीं देता है कि यह जल्द ही ओवरराइट हो जाएगा। इससे पहले कि स्ट्रिंग नष्ट होने से पहले इसके प्रत्येक चरित्र को अधिलेखित करके गोपनीयता को बेहतर ढंग से प्रबंधित करें ;-)
क्रिस्टोफ़े

1
@ ErikEidt मैं "C / C ++" बोलने की समस्या की ओर ध्यान आकर्षित करने की कोशिश कर रहा था, क्योंकि यह वास्तव में एक "बात" थी, लेकिन यह नहीं है: "C / C ++ के लिए रनटाइम में कंपाइलर आमतौर पर एक स्टैक फ्रेम आवंटित करेगा। उस विधि के लिए जो आवश्यकतानुसार बड़ी हो ” लेकिन C में विधियाँ नहीं हैं। इसके कार्य हैं। ये अलग-अलग हैं, खासकर C ++ में।
tchrist

7
" इसके विपरीत, जावा में स्थानीय वस्तुओं का होना संभव नहीं है: सभी वस्तुएं हीप ऑब्जेक्ट्स हैं, और सभी लोकल / फॉर्मल या तो संदर्भ चर या आदिम प्रकार (btw, वही स्टेटिक्स के लिए सच है) " - ध्यान दें कि यह। पूरी तरह से सच नहीं है, खासकर विधि स्थानीय चर के लिए नहीं। एस्केप विश्लेषण वस्तुओं को स्टैक में आवंटित कर सकता है।
बोरिस ने

1
" सबसे अच्छा संकलक स्थानीय चर स्लॉट का पुन: उपयोग कर सकता है, लेकिन (सी / सी ++ के विपरीत) केवल अगर उनका प्रकार समान है। “बस गलत है। बायटेकोड स्तर पर, स्थानीय चर को असाइन किया जा सकता है और जो भी आप चाहते हैं, उसके साथ पुन: असाइन किया जा सकता है, एकमात्र बाधा यह है कि बाद का उपयोग नवीनतम निर्दिष्ट आइटम के प्रकार के अनुकूल है। स्थानीय चर स्लॉट का पुन: उपयोग करना आदर्श है, जैसे { int x = 42; String s="blah"; } { long y = 0; }, longचर दोनों चर के स्लॉट का पुन: उपयोग करेगा , xऔर sसभी आमतौर पर उपयोग किए जाने वाले संकलक ( javacऔर ecj) के साथ।
होल्गर

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

27

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


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

16
@ रुबरडैक सच है, लेकिन उस मामले में हममें से बाकी लोगों को इसे कभी नहीं देखना चाहिए, तो इससे कोई फर्क नहीं पड़ता कि हम क्या सोचते हैं। क्या एक वयस्क कोडर और एक सहमति संकलक अपने स्वयं के क्यूबिकल की गोपनीयता में उठते हैं, किसी और की चिंता नहीं है।
कैंडिड_ओरेंज

@candied_orange मुझे डर है कि मैं यह नहीं :( देखभाल विस्तृत करने के मिल सकता है?
doubleOrt

@doubleOrt का मतलब था कि मध्यवर्ती रिफैक्टिंग चरण वास्तविक और आवश्यक हैं लेकिन निश्चित रूप से स्रोत नियंत्रण में सुनिश्चित होने की आवश्यकता नहीं है जहां हर कोई इसे देख सकता है। चेक-इन करने से पहले बस रिफैक्टरिंग समाप्त करें।
candied_orange

@candied_orange ओह, सोचा था कि आप बहस कर रहे थे और रबरकुक के तर्क का विस्तार नहीं कर रहे थे।
doubleOrt

17

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

एक मामला है, जहां मुझे यह उपयोगी लगता है - एक switchबयान में! कभी-कभी आप एक चर घोषित करना चाहते हैं case:

switch (op) {
    case ADD:
        int result = a + b;
        System.out.printf("%s + %s = %s\n", a, b, result);
        break;
    case SUB:
        int result = a - b;
        System.out.printf("%s - %s = %s\n", a, b, result);
        break;
}

हालांकि, यह विफल हो जाएगा:

error: variable result is already defined in method main(String[])
            int result = a - b;

switch बयान अजीब हैं - वे नियंत्रण वक्तव्य हैं, लेकिन उनके पतन के कारण वे स्कोप का परिचय नहीं देते हैं।

तो - आप अपने आप को स्कैप्स बनाने के लिए ब्लॉक का उपयोग कर सकते हैं:

switch (op) {
    case ADD: {
        int result = a + b;
        System.out.printf("%s + %s = %s\n", a, b, result);
    } break;
    case SUB: {
        int result = a - b;
        System.out.printf("%s - %s = %s\n", a, b, result);
    } break;
}

6
  • सामान्य मामला:

क्या कोई ऐसा मामला है जहां केवल वैरिएबल स्कोप को कम करने के लिए ब्लॉक का उपयोग करना समझ में आता है?

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

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

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

यह समझ में आ सकता है, लेकिन यह बहुत दुर्लभ है।

  • आपका उपयोग मामला:

यहाँ आपका कोड है:

KeyManagerFactory keyManager = KeyManagerFactory.getInstance("SunX509");
Keystore keyStore = KeyStore.getInstance("JKS");

{
    char[] password = getPassword();
    keyStore.load(new FileInputStream(keyStoreLocation), password);
    keyManager.init(keyStore, password);
}

आप एक निर्माण FileInputStreamकर रहे हैं, लेकिन आप इसे कभी बंद नहीं कर रहे हैं।

इसे हल करने का एक तरीका संसाधनों के साथ कथन का उपयोग करना है । यह स्कोप करता है InputStream, और यदि आप चाहें तो इस ब्लॉक का उपयोग अन्य चर के दायरे को कम करने के लिए भी कर सकते हैं (कारण के अनुसार, क्योंकि ये लाइनें संबंधित हैं):

KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
Keystore keyStore = KeyStore.getInstance("JKS");

try (InputStream fis = new FileInputStream(keyStoreLocation)) {
    char[] password = getPassword();
    keyStore.load(fis, password);
    keyManager.init(keyStore, password);
}

(यह भी अक्सर रास्ते के getDefaultAlgorithm()बजाय का उपयोग करने के लिए बेहतर है SunX509।)

इसके अलावा, जबकि कोड को अलग-अलग तरीकों से अलग करने की सलाह आम तौर पर ध्वनि है। यह शायद ही कभी इसके लायक है अगर यह सिर्फ 3 लाइनों के लिए है (यदि कुछ भी हो, तो यह एक ऐसा मामला है जहां एक अलग विधि बनाने से पठनीयता में बाधा आती है)।


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

2

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

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

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

सतही तरीकों के लिए सुझाव नहीं

यह आपको केवल गुंजाइश कम करने के लिए जबरदस्ती तरीके बनाने का सुझाव देने के लिए नहीं है। यकीनन यह उतना ही बुरा या बुरा है, और मैं जो सुझाव दे रहा हूं, वह किसी अज्ञात निजी "हेल्पर" तरीकों की जरूरत नहीं है, जो गुमनाम स्कोप की आवश्यकता से अधिक है। यह कोड के बारे में बहुत अधिक सोच रहा है क्योंकि यह अब है और यह सोचने के तरीके की तुलना में चर की गुंजाइश को कम करने के लिए कि कैसे इंटरफ़ेस स्तर पर समस्या को वैचारिक रूप से हल करने के तरीकों से साफ-सुथरी उपज प्राप्त होती है, स्थानीय फ़ंक्शन की कम दृश्यता स्वाभाविक रूप से ब्लॉक के गहरे घोंसले के बिना बताती है। और इंडेंटेशन के 6+ स्तर। मैं ब्रूनो से सहमत हूं कि आप एक फ़ंक्शन में कोड की 3 पंक्तियों को बलपूर्वक हटाकर कोड पठनीयता में बाधा डाल सकते हैं, लेकिन यह इस धारणा से शुरू हो रहा है कि आप अपने मौजूदा कार्यान्वयन के आधार पर आपके द्वारा बनाए जाने वाले कार्यों को विकसित कर रहे हैं, कार्यान्वयन में उलझी बिना कार्यों को डिजाइन करने के बजाय। यदि आप इसे बाद का तरीका करते हैं, तो मुझे अनाम ब्लॉकों की बहुत कम आवश्यकता है जो किसी दिए गए तरीके के भीतर चर दायरे को कम करने से परे कोई उद्देश्य नहीं देते हैं जब तक कि आप किसी भी तरह से हानिरहित कोड की कुछ कम लाइनों द्वारा चर के दायरे को कम करने की कोशिश नहीं कर रहे हैं जहां इन अनाम ब्लॉकों का विदेशी परिचय यकीनन उतना ही बौद्धिक उपरि योगदान देता है जितना वे हटाते हैं।

आगे भी न्यूनतम स्कोप कम करने की कोशिश की जा रही है

यदि स्थानीय वैरिएबल स्कोप को पूर्णतम तक कम करना सार्थक था, तो इस तरह कोड की एक विस्तृत स्वीकृति होनी चाहिए:

ImageIO.write(new Robot("borg").createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())), "png", new File(Db.getUserId(User.handle()).toString()));

... जैसा कि राज्य की न्यूनतम दृश्यता का कारण बनता है, पहली बार में उन्हें संदर्भित करने के लिए चर भी नहीं बना रहा है। मैं हठधर्मिता के रूप में नहीं आना चाहता हूं, लेकिन मुझे लगता है कि व्यावहारिक समाधान अनाम ब्लॉकों से बचने के लिए है जब संभव हो तो बस ऊपर दिए गए कोड की राक्षसी रेखा से बचना है, और यदि वे उत्पादन के संदर्भ से बिल्कुल जरूरी लगते हैं शुद्धता और एक कार्य के भीतर अपरिवर्तनीयता बनाए रखने का परिप्रेक्ष्य, तो मैं निश्चित रूप से सोचता हूं कि आप अपने कोड को कार्यों में कैसे व्यवस्थित कर रहे हैं और अपने इंटरफेस को डिजाइन करना फिर से जांचने योग्य है। स्वाभाविक रूप से यदि आपकी विधि 400 लाइनों की लंबी है और एक चर का दायरा जरूरत से ज्यादा कोड की 300 लाइनों को दिखाई देता है, तो यह एक वास्तविक इंजीनियरिंग समस्या हो सकती है, लेकिन यह जरूरी नहीं है कि अनाम ब्लॉकों के साथ हल करने के लिए एक समस्या है।

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

कम करने की गुंजाइश का व्यावहारिक उपयोग

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


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

2

क्या कोई ऐसा मामला है जहां केवल वैरिएबल स्कोप को कम करने के लिए ब्लॉक का उपयोग करना समझ में आता है?

मुझे लगता है कि प्रेरणा एक ब्लॉक शुरू करने के लिए पर्याप्त कारण है, हाँ।

जैसा कि केसी ने कहा, ब्लॉक एक "कोड गंध" है जो इंगित करता है कि आप ब्लॉक को एक फ़ंक्शन में निकालने से बेहतर हो सकते हैं। लेकिन आप नहीं कर सकते।

जॉन कार्मार्क ने 2007 में इनलाइन कोड पर एक मेमो लिखा था। उनका समापन सारांश

  • यदि किसी फ़ंक्शन को केवल एक ही स्थान से बुलाया जाता है, तो उसे inlining पर विचार करें।
  • यदि किसी फ़ंक्शन को कई स्थानों से कॉल किया जाता है, तो देखें कि क्या एक ही स्थान पर काम करने की व्यवस्था करना संभव है, शायद झंडे और इनलाइन के साथ।
  • यदि किसी फ़ंक्शन के कई संस्करण हैं, तो अधिक, संभवतः डिफ़ॉल्ट रूप से, मापदंडों के साथ एकल फ़ंक्शन बनाने पर विचार करें।
  • यदि कार्य विशुद्ध रूप से कार्यात्मक के करीब है, तो वैश्विक स्थिति के कुछ संदर्भों के साथ, इसे पूरी तरह से कार्यात्मक बनाने का प्रयास करें।

तो सोचो , उद्देश्य के साथ एक विकल्प बनाओ, और (वैकल्पिक) आपके द्वारा बनाई गई पसंद के लिए अपनी प्रेरणा का वर्णन करते हुए सबूत छोड़ दें।


1

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

मैं मुख्य रूप से एक C # प्रोग्रामर हूं, लेकिन मैंने सुना है कि जावा में, एक पासवर्ड वापस करना जैसा char[]कि आपको उस समय को कम करने की अनुमति देगा जब पासवर्ड मेमोरी में रहेगा। इस उदाहरण में, यह मदद नहीं करेगा, क्योंकि कचरा संग्रहकर्ता को उस क्षण से सरणी एकत्र करने की अनुमति है जो उपयोग में नहीं है, इसलिए यह मायने रखता है कि क्या पासवर्ड गुंजाइश नहीं छोड़ता है। मैं यह तर्क नहीं दे रहा हूं कि आपके साथ किए जाने के बाद सरणी को साफ़ करना व्यवहार्य है या नहीं, लेकिन इस मामले में, यदि आप इसे करना चाहते हैं, तो वेरिएबल को स्कूप करना समझ में आता है:

{
    char[] password = getPassword();
    try{
        keyStore.load(new FileInputStream(keyStoreLocation), password);
        keyManager.init(keyStore, password);
    }finally{
        Arrays.fill(password, '\0');
    }
}

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

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

एक और उदाहरण मैं सोच सकता हूं कि जब आपके पास दो चर होते हैं जिनका समान नाम और अर्थ होता है, लेकिन आप एक के साथ और फिर दूसरे के साथ काम करते हैं, और आप उन्हें अलग रखना चाहते हैं। मैंने यह कोड C # में लिखा है:

{
    MethodBuilder m_ToString = tb.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, typeofString, Type.EmptyTypes);
    var il = m_ToString.GetILGenerator();
    il.Emit(OpCodes.Ldstr, templateType.ToString()+":"+staticType.ToString());
    il.Emit(OpCodes.Ret);
    tb.DefineMethodOverride(m_ToString, m_Object_ToString);
}
{
    PropertyBuilder p_Class = tb.DefineProperty("Class", PropertyAttributes.None, typeofType, Type.EmptyTypes);
    MethodBuilder m_get_Class = tb.DefineMethod("get_Class", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, typeofType, Type.EmptyTypes);
    var il = m_get_Class.GetILGenerator();
    il.Emit(OpCodes.Ldtoken, staticType);
    il.Emit(OpCodes.Call, m_Type_GetTypeFromHandle);
    il.Emit(OpCodes.Ret);
    p_Class.SetGetMethod(m_get_Class);
    tb.DefineMethodOverride(m_get_Class, m_IPattern_get_Class);
}

आप तर्क दे सकते हैं कि मैं केवल ILGenerator il;विधि के शीर्ष पर घोषित कर सकता हूं , लेकिन मैं विभिन्न वस्तुओं (थोड़े कार्यात्मक दृष्टिकोण) के लिए चर का पुन: उपयोग नहीं करना चाहता हूं। इस स्थिति में, ब्लॉक किए गए कार्यों को अलग-अलग करना आसान बना देता है, दोनों ही वाक्यात्मक और नेत्रहीन। यह यह भी बताता है कि ब्लॉक के बाद, मैं साथ हूं ilऔर कुछ भी इसे एक्सेस नहीं करना चाहिए।

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

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