बेस्ट प्रैक्टिस - रैपिंग अगर फंक्शन कॉल के आसपास हो तो फंक्शन में गार्ड से जल्दी बाहर निकलना


9

मुझे पता है कि यह बहुत उपयोग-मामला विशिष्ट हो सकता है, लेकिन मैं खुद को इस बात से बहुत बार आश्चर्यचकित पाता हूं। क्या आमतौर पर पसंदीदा वाक्यविन्यास है।

मैं यह नहीं पूछ रहा हूं कि किसी फ़ंक्शन में सबसे अच्छा तरीका क्या है, मैं पूछ रहा हूं कि मुझे जल्दी से बाहर निकलना चाहिए या मुझे सिर्फ फ़ंक्शन को कॉल नहीं करना चाहिए।

लपेटें अगर चारों ओर समारोह कॉल


if (shouldThisRun) {
  runFunction();
}

है अगर ( गार्ड ) समारोह में

runFunction() {
  if (!shouldThisRun) return;
}

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


एक उदाहरण है

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

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



3
@gnat नहीं, यह प्रश्न अनिवार्य रूप से 'आरंभिक निकास में पसंदीदा वाक्यविन्यास क्या है' जबकि मेरा 'क्या मुझे जल्दी बाहर निकलना चाहिए या मुझे सिर्फ समारोह नहीं करना चाहिए'
मैथ्यू मुलिन

4
आप डेवलपर्स पर भरोसा नहीं कर सकते हैं, यहां तक ​​कि खुद को , हर जगह फ़ंक्शन की पूर्व-स्थितियों की जांच करने के लिए, जिसे यह कहा जाता है, को सही ढंग से जांचने के लिए नहीं। इस कारण से, मेरा सुझाव है कि यदि ऐसा करने की क्षमता है तो फ़ंक्शन आंतरिक रूप से किसी भी आवश्यक शर्तों को मान्य करता है।
TZHX

"यदि केवल स्थिति बदली गई है तो मैं केवल अपडेट की गई स्थिति चाहता हूं" - यदि आप उसी स्थिति में अपडेट किए गए (= परिवर्तित) स्थिति चाहते हैं? काफी गोलाकार लगता है। क्या आप स्पष्ट कर सकते हैं कि आपका क्या मतलब है, इसलिए मैं इस पर अपने जवाब में एक सार्थक उदाहरण जोड़ सकता हूं?
डॉक ब्राउन

उदाहरण के लिए @DocBrown चलो कहते हैं कि मैं सिंक में दो अलग-अलग वस्तुओं की स्थिति गुण रखना चाहता हूं। जब या तो ऑब्जेक्ट में परिवर्तन होता है, तो मैं सिंकस्टैटस () कहता हूं - लेकिन यह कई अलग-अलग फ़ील्ड परिवर्तनों (न केवल स्थिति फ़ील्ड) के लिए ट्रिगर किया जा सकता है।
मैथ्यू मुलिन

जवाबों:


15

एक फ़ंक्शन कॉल के आसपास अगर रैपिंग होती है:
यह तय करना है कि क्या फ़ंक्शन को बिल्कुल बुलाया जाना चाहिए, और यह आपके प्रोग्राम की निर्णय लेने की प्रक्रिया का हिस्सा है।

फ़ंक्शन में गार्ड क्लॉज (शुरुआती रिटर्न):
यह अमान्य मापदंडों के साथ बुलाया जाने से बचाने के लिए है

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

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

यह पूछने के लिए एक अच्छा सवाल है, और सवालों के सेट के भीतर आता है जो अमूर्तता के स्तर को पहचानते हैं। प्रत्येक समारोह अमूर्त की एक भी स्तर पर संचालित करना चाहिए, और दोनों कार्यक्रम तर्क और समारोह में समारोह तर्क होने के लिए आप गलत लगता है - यह है कि वे कर रहे हैं अमूर्त के विभिन्न स्तरों पर। फ़ंक्शन स्वयं एक निम्न स्तर है।

इन अलग रखने से, आप यह सुनिश्चित करते हैं कि आपका कोड लिखना, पढ़ना और बनाए रखना आसान होगा।


बहुत बढ़िया जवाब। मुझे यह पसंद है कि यह मुझे इस बारे में सोचने का एक स्पष्ट तरीका दे। यदि बाहर होना चाहिए क्योंकि यह 'निर्णय लेने की प्रक्रिया का हिस्सा' है, तो यह है कि क्या फ़ंक्शन को पहले स्थान पर बुलाया जाना चाहिए। और स्वाभाविक रूप से फ़ंक्शन के साथ कुछ भी नहीं करना है। राय के जवाब को सही मानने में अजीब लगता है, लेकिन मैं कुछ घंटों में फिर से देखूंगा और ऐसा करूंगा।
मैथ्यू मुलिन

यदि यह मदद करता है, तो मैं इसे "राय" के रूप में नहीं मानता। मैं ध्यान देता हूं कि यह "गलत" लगता है, लेकिन ऐसा इसलिए है क्योंकि अमूर्तता के विभिन्न स्तर अलग नहीं हैं। आपके प्रश्न से मुझे जो मिला है, वह आप देख सकते हैं कि यह 'सही' नहीं है, लेकिन क्योंकि आप अमूर्त के स्तरों के बारे में नहीं सोच रहे हैं, यह निर्धारित करना कठिन है, इसलिए यह कुछ ऐसा है जिसे आप शब्दों में डालने के लिए संघर्ष करते हैं।
बाल्ड्रिक

7

आपके पास दोनों हो सकते हैं - एक फ़ंक्शन जो मापदंडों की जांच नहीं करता है, और दूसरा वह जो करता है, इस तरह (शायद कॉल के बारे में कुछ जानकारी वापस कर रहा है):

bool tryRunFunction(...)
{
    bool shouldThisRun = /* some logic using data not available inside "runFunction"*/;
    if (shouldThisRun)
        runFunction();
    return shouldThisRun;
}

इस तरह, आप पुन: प्रयोज्य प्रदान करके डुप्लिकेट तर्क से बच सकते हैं tryRunFunctionऔर अभी भी आपका मूल (शायद शुद्ध) फ़ंक्शन है जो चेक को अंदर नहीं करता है।

ध्यान दें कि कभी-कभी आपको tryRunFunctionविशेष रूप से एकीकृत चेक के साथ एक फ़ंक्शन की आवश्यकता होगी , ताकि आप चेक को एकीकृत कर सकें runFunction। या फिर आपको अपने कार्यक्रम में कहीं भी चेक का पुन: उपयोग करने की कोई आवश्यकता नहीं है, जिस स्थिति में आप इसे कॉलिंग फ़ंक्शन में रहने दे सकते हैं।

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


1
स्वीकार करना है, "tryXXX ()" मुहावरा हमेशा थोड़ा हटकर लग रहा था और यह यहाँ अनुचित है। आप एक संभावित त्रुटि की उम्मीद करते हुए कुछ करने की कोशिश नहीं कर रहे हैं। अगर यह गंदा है तो आप अपडेट कर रहे हैं।
user949300

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

"ड्राईरुन" नाम की कोई चीज़ नहीं है? कम या ज्यादा साइड इफेक्ट के बिना एक नियमित निष्पादन हो जाता है। साइड इफेक्ट्स को कैसे निष्क्रिय करें एक और कहानी है
Laiv

3

जैसा कि कौन तय करता है कि क्या चलाना है, इसका जवाब जीआरएएसपी से है , जो "सूचना विशेषज्ञ" है जो जानता है।

एक बार जब आप तय कर लेते हैं कि, स्पष्टता के लिए फ़ंक्शन का नाम बदलने पर विचार करें।

कुछ इस तरह से, अगर फ़ंक्शन तय करता है:

 ensureUpdated()
 updateIfDirty()

या, यदि कॉलर को निर्णय लेना है:

 writeStatus()

2

मैं @ बाल्ड्रिक के उत्तर पर विस्तार करना चाहता हूं।

आपके प्रश्न का कोई सामान्य उत्तर नहीं है। यह फ़ंक्शन के अर्थ और अनुबंध की स्थिति पर निर्भर करता है।

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

तो, एक कॉलिंग साइट एक कॉल को छोड़ सकती है updateStatus()यदि यह जानती है कि (उसके डोमेन क्षितिज के अंदर) प्रासंगिक कुछ भी नहीं बदला है। वह परिस्थितियां हैं जहां कॉल को एक उपयुक्त ifनिर्माण से घिरा होना चाहिए ।

updateStatus()फ़ंक्शन के अंदर , ऐसी स्थितियां हो सकती हैं जहां यह फ़ंक्शन पता लगाता है (इसके डोमेन क्षितिज के अंदर डेटा से) जो कुछ भी नहीं करना है, और यही वह है जहां इसे जल्दी लौटना चाहिए।

तो, प्रश्न हैं:

  • बाहर के दृश्य से, जब फ़ंक्शन को कॉल करने की अनुमति दी जाती है, तो फ़ंक्शन के अनुबंध को ध्यान में रखा जाता है?
  • फ़ंक्शन के अंदर, क्या ऐसी परिस्थितियां हैं जहां यह किसी भी वास्तविक काम के बिना जल्दी लौट सकता है?
  • क्या यह शर्त है कि फ़ंक्शन को कॉल करना है या नहीं, जल्दी से फ़ंक्शन के आंतरिक डोमेन से संबंधित हैं या बाहर से?

एक updateStatus()फ़ंक्शन के साथ , मैं दोनों को देखने की उम्मीद करूंगा, कॉलिंग साइटें जो कुछ भी नहीं बदलती हैं, कॉल को छोड़ देना, और "कुछ भी नहीं बदला" स्थितियों के लिए कार्यान्वयन की जाँच करना, भले ही इस तरह की स्थिति कुछ ही समय में दो बार जाँच की जाती है, दोनों अंदर और बाहर।


2

कई अच्छे स्पष्टीकरण हैं। लेकिन मैं असामान्य तरीके से देखना चाहता हूं: मान लें कि आप इस तरह से उपयोग करते हैं:

if (shouldThisRun) {
   runFunction();
}

runFunction() {
   if (!shouldThisRun) return;
}

और आपको runFunctionइस तरह से किसी अन्य फ़ंक्शन को कॉल करने की आवश्यकता है :

runFunction() {
   if (!shouldThisRun) return;
   someOtherfunction();
}

आप क्या करेंगे? क्या आप सभी मान्यताओं को ऊपर से नीचे तक कॉपी करते हैं?

someOtherfunction() {
   if (!shouldThisRun) return;
}

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

public someFunction() {
   if (shouldThisRun) {
      runFunction();
   }
}

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