2010-03-06 14 views
8

कोडिंग के कई साल मुझे विश्वास है और अगर सशर्त कोडिंग के इस प्रकार तक पहुँचने की कोशिश करने के लिए लाया है: (सी में प्रदर्शन किया है, लेकिन यह लगभग किसी भी भाषा के लिए प्रासंगिक है)यदि शर्तों के लिए सबसे अच्छा कोडिंग अभ्यास क्या है?

if(a <= 0) 
     return false; 
if(strlen(str) <= a) 
     return false; 
if(str[a] == NULL) 
     return false; 
return true; 

जो मुझे लगता है ज्यादा से ज्यादा पढ़ी जा सकती है अगले कोडिंग नमूना, विशेष रूप से स्थिति की एक विशाल संख्या पर:

if(a >0) 
{ 
    if(strlen(str) > a) 
    { 
      if(str[a] != NULL) 
      { 
       return true; 
      } 
     } 
    } 

ऊपरी कोड और अधिक पठनीय, पिछले कोड मेरा मानना ​​है बड़े की स्थिति, और आप अपने आप को बहुत से बंद हो रहा हो सकता है "}" पर है जबकि एक बेहतर प्रदर्शन कोड के लिए संकलित।

आपको कौन सा लगता है कि इसका उपयोग करना बेहतर है?

+1

दूसरा एक पठनीय प्रारूप होगा। और आप इन तीन अभिव्यक्तियों को && स्थिति में प्राप्त कर सकते हैं। तो, अगर आप हालत में केवल एक का उपयोग करेंगे। – Pavunkumar

+1

शायद मेरे कोडिंग नमूना प्रश्न के लिए "सही" नहीं थे। मुझे पता है कि आप इसे एक लाइन की स्थिति डाल सकते हैं। लेकिन मैं कोडिंग आदत के बारे में पूछने की कोशिश कर रहा हूं। – aviv

उत्तर

2

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

  • परीक्षण समारोह
  • में किसी भी अन्य कोड के पहले आना चाहिए अगर एक पूर्व शर्त के लिए एक परीक्षण विफल रहता है, समारोह तुरंत लौट जाना

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

नमूना कोड:

// function contract 
// 
// pre-conditions: 
// 
// o bar must not be zero 
// o foo_ptr must not be NULL 
// o foo_ptr must refer to a foo variant of type blue_foo 
// 
// ... 

Foo *foo_blue_init_with_bar(Foo *foo_ptr, int bar, foo_status *status) { 

    // ***** Test Pre-conditions ***** 

    // bar must not be zero 
    if (bar == 0) { 
     if (status != NULL) *status = FOO_STATUS_INVALID_BAR; 
     return NULL; 
    } 

    // foo_ptr must not be NULL 
    if (foo_ptr == NULL) { 
     if (status != NULL) *status = FOO_STATUS_INVALID_FOO_POINTER; 
     return NULL; 
    } 

    // foo_ptr must refer to a foo variant of type blue_foo 
    if (foo_ptr->type != blue_foo) { 
     if (status != NULL) *status = FOO_STATUS_INVALID_FOO_VARIANT; 
     return NULL; 
    } 

    // ***** Actual Work Goes Here ***** 

    ... 

} // end foo_blue_init_with_bar 

दूसरी ओर, यदि आप डिजाइन का पालन नहीं करते अनुबंध करके, तो यह शायद निजी प्राथमिकता का मामला माना जा सकता है।

5

व्यक्तिगत तौर पर मैं पहले खंड के साथ जाने (इस उदाहरण में कोड सिर्फ प्रदर्शन यह सचमुच नहीं लेते के लिए है)। जितनी जल्दी हो सके वापसी करें।

+0

मुझे लगता है कि एक सभ्य कंपाइलर दूसरे मामले को अनुकूलित करेगा ताकि यह वैसे भी बदले में वापस आ जाएगा। नहीं? – amn

+0

जिन्होंने इस उत्तर में संकलक अनुकूलन के बारे में कुछ भी कहा? – Anurag

0

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

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

+1

फ़ंक्शन के अंदर 1 रिटर्न स्टेटमेंट के लिए यह सर्वोत्तम अभ्यास क्यों है? –

+1

यह _old_ "axiom" है, जिसमें एक विधि में केवल एक वापसी होने से जटिलता कम हो जाती है। इन दिनों आम नहीं है, लेकिन अभी भी इसके बारे में बंधे हैं। –

8

प्रश्न यहां वास्तव में स्पष्ट नहीं है। हम इस तुलना करने के लिए कर रहे हैं:

if (c1) return false; 
if (c2) return false; 
if (c3) return false; 
return true; 
इस के साथ

:

if (!c1) { 
    if (!c2) { 
    if (!c3) { 
     return true; 
    } 
    } 
} 
return false; 

तब मैं न तो के लिए मतदान होगा। बजाय यह करें:

return !c1 && !c2 && !c3; 

प्रश्न के बारे में है या नहीं, कई रिटर्न स्वीकार्य हैं, तो यह सवाल पहले से ही चर्चा की गई है, तो (देखें: Should a function have only one return statement)

2

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

if(a > 0 
     && strlen(str) > a 
     && str[a] != NULL) 
    { 
     return true; 
    } 

या, जब एक बूलियन लौटने (जो एक विशेष मामला है तो आपके प्रश्न पर लागू नहीं हो सकता है):

return (a > 0 
     && strlen(str) > a 
     && str[a] != NULL); 
1

की स्थिति समान या संबंधित अर्थ विज्ञान है, तो यह शायद बेहतर है if एस के समूह के बजाय तार्किक अभिव्यक्ति का उपयोग करें।

return a > 0 && strlen(str) > a && str[a] != NULL; 

लेकिन आप के आयोजन के if, सबसे अच्छा तरीका उपयोग करने के लिए जब अक्सर (यदि हमेशा नहीं) शाखाओं if की प्रकृति पर निर्भर करता है की तरह।

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

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

उपरोक्त फिर से शुरू करने के लिए: नेस्टेड if एस से बचें। उन्हें पढ़ना मुश्किल है। "असंतुलित" से बचें if एस। उन्हें पढ़ना भी मुश्किल है। "फ्लैट" ब्रांचिंग शैली को पसंद करें जो पहले साधारण मामलों से संबंधित है और तुरंत return या continue करके प्रोसेसिंग समाप्त कर देता है।

0

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

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

isPositive = a > 0; 
isStringLonger = str.length() > a; 
isCharacterNonNull = str[a] != NULL; 

return isPositive && isStringLonger && isCharacterNonNull; 

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

वैकल्पिक रूप से, जब ये तीन चर कई दिखाई देते हैं, तो मैं इसे वापस करने से पहले उन्हें एक चर में जोड़ता हूं।

isValidString = isPositive && isStringLonger && isCharacterNonNull; 
return isValidString; 

जहां तक ​​कई वापसी बयान जाओ, मैं पाया है कि अधिकांश बयान करने के लिए एक शर्त है प्रत्यय लगाना की रूबी की तरह बहुत साफ है और पठनीय है।

return false if a <= 0 
return false if str.length() <= a 
return false if !str[a].nil? 
return true 
0

आपके दो नमूने अलग-अलग चीजें करते हैं (नीचे कोड देखें)। मैं दूसरी पसंद करेंगे अगर यह (नीचे की तरह लिखा गया था शायद कम ब्रैकेट के साथ छोड़कर।

if((a>0) && (strlen(str) > a) && (str[a] != NULL)) 
{ 
    return true; 
} 

या

return ((a>0) && (strlen(str) > a) && (str[a] != NULL)) 

की तरह लिखा आपके प्रश्न का उत्तर करने के लिए। मैं पसंद पहले (जब तक उपरोक्त कोड सही है) और मैं हमेशा

  1. कम टैब्बिंग। मैं जितना संभव हो उतना सब कुछ पसंद करता हूं जो आपका दूसरा उदाहरण टूटता है (लेकिन मेरा नहीं)
  2. यदि संभव हो तो शीर्ष पर वापस लौटें यदि (cond) वापसी blah; अन्य {कोड(); }
  3. अगर (cond) { कोड() नीचे

    पर शीर्ष और लंबे समय तक कोड में शॉर्ट कोड है; } अन्य यदि (cond2) { कोड(); कोड(); } अन्य { कोड(); कोड(); कोड(); }

संबंधित मुद्दे