अगर अंकल बॉब के क्लीन कोड सिद्धांतों का पालन करने के लिए मैं और-और की श्रृंखला को कैसे संपादित करूं?


45

मैं अंकल बॉब के क्लीन कोड सुझावों का पालन करने की कोशिश कर रहा हूं और विशेष रूप से तरीकों को छोटा रखने के लिए।

मैं अपने आप को इस तर्क को छोटा करने में असमर्थ पाता हूँ:

if (checkCondition()) {addAlert(1);}
else if (checkCondition2()) {addAlert(2);}
else if (checkCondition3()) {addAlert(3);}
else if (checkCondition4()) {addAlert(4);}

मैं योग्‍यता को हटा नहीं सकता और इस तरह पूरी चीज़ को छोटे-छोटे टुकड़ों में अलग कर सकता हूँ, "और" का कारण "और" यदि "प्रदर्शन" में मदद करता है - उन स्थितियों का मूल्यांकन करना महंगा है और अगर मैं नीचे की स्थितियों का मूल्यांकन करने से बच सकता हूँ, तो पहले वाले में से एक का कारण बनें। सच है, मैं उनसे बचना चाहता हूं।

शब्दार्थ भी, यदि पिछली मुलाकात हुई थी, तो अगली स्थिति का मूल्यांकन करना, व्यावसायिक दृष्टिकोण से कोई मतलब नहीं है।


संपादित करें: इस प्रश्न को (यदि अन्य) को संभालने के लिए सुरुचिपूर्ण तरीके के संभावित डुप्लिकेट के रूप में पहचाना गया था ।

मेरा मानना ​​है कि यह एक अलग प्रश्न है (आप उन प्रश्नों के उत्तरों की तुलना करके भी देख सकते हैं)।

  • मेरा प्रश्न पहली स्वीकृति की स्थिति को जल्दी से समाप्त करने के लिए जाँच कर रहा है
  • जुड़ा हुआ प्रश्न कुछ करने के लिए सभी शर्तों को स्वीकार करने की कोशिश कर रहा है। (इस सवाल के जवाब में बेहतर देखा गया: https://softwareengineering.stackexchange.com/a/122625/96955 )

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

38
इस कोड में कुछ भी गलत नहीं है। यह बहुत पठनीय और अनुसरण करने में आसान है। जो कुछ भी आप इसे सिकोड़ते हैं, वह अप्रत्यक्ष रूप से जोड़ने वाला है और इसे समझना कठिन है।
17 की 26

20
आपका कोड ठीक है। अपनी शेष ऊर्जा को कुछ और अधिक उत्पादक बनाने में लगाएं ताकि इसे और छोटा किया जा सके।
रॉबर्ट हार्वे

5
यदि यह वास्तव में सिर्फ 4 स्थितियां हैं, तो यह ठीक है। अगर यह वास्तव में 12 या 50 जैसा कुछ है, तो आप शायद इस एक विधि की तुलना में उच्च स्तर पर रिफ्लेक्टर करना चाहते हैं।
जिमीजैम

9
अपना कोड बिल्कुल वैसा ही छोड़ दें। आपके माता-पिता ने आपको जो बताया, उसे सुनिए: सड़क पर बच्चों को मिठाई देने वाले किसी भी चाचा पर विश्वास न करें। @ हाईवे काफी मजेदार है, कोड में "सुधार" के विभिन्न प्रयासों ने इसे बहुत बड़ा, अधिक जटिल और कम पठनीय बना दिया है।
gnasher729

जवाबों:


81

आदर्श रूप से मुझे लगता है कि आपको अलर्ट कोड / संख्या को अपने तरीके से प्राप्त करने के लिए अपना तर्क निकालना चाहिए। तो आपका मौजूदा कोड नीचे की ओर सभी तरह से कम हो गया है

{
    addAlert(GetConditionCode());
}

और आपके पास GetConditionCode है () स्थितियों की जाँच करने के लिए तर्क को एन्क्रिप्ट करता है। शायद जादू की संख्या की तुलना में एनम का उपयोग करना बेहतर है।

private AlertCode GetConditionCode() {
    if (CheckCondition1()) return AlertCode.OnFire;
    if (CheckCondition2()) return AlertCode.PlagueOfBees;
    if (CheckCondition3()) return AlertCode.Godzilla;
    if (CheckCondition4()) return AlertCode.ZombieSharkNado;
    return AlertCode.None;
}

2
यदि आप इसका वर्णन करना संभव करते हैं, जैसा कि आप वर्णन करते हैं (मुझे संदेह है कि यह नहीं हो सकता है, मुझे लगता है कि ओपी सरलता के लिए चर छोड़ रहा है), यह कोड को नहीं बदलता है, जो अपने आप में ठीक है, लेकिन कोड एर्गोनॉमिक्स और थोड़ा पठनीयता जोड़ता है + 1
ओपा

17
उन अलर्ट कोडों के साथ, मैं धन्यवाद देता हूं कि एक बार में केवल एक कोड वापस किया जा सकता है
जोश भाग

12
यह एक स्विच स्टेटमेंट के उपयोग के लिए भी एक आदर्श मैच है - यदि वह ओपी की भाषा में उपलब्ध है।
फ्रैंक हॉपकिंस

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

6
इस पुन: कार्यान्वयन के साथ एक मुद्दा यह है कि यह addAlertफर्जी अलर्ट की स्थिति के लिए फ़ंक्शन को जांचने की आवश्यकता बनाता है AlertCode.None
डेविड हैमेन

69

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

"सरल" करने के लिए कोई भी प्रयास वास्तव में चीजों को जटिल करेगा।

बेशक, आप elseकीवर्ड को प्रतिस्थापित कर सकते हैं returnजैसा कि अन्य ने सुझाव दिया है, लेकिन यह सिर्फ शैली की बात है, जटिलता में बदलाव नहीं।


एक तरफ:

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

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


2
मेरा तर्क है कि एक साधारण ( एक ) को हटाने के बाद else ifएक आंतरिक के साथ प्रतिस्थापित करना कोड को पढ़ने के लिए और अधिक कठिन बना सकता है । जब कोड कहता है , मुझे तुरंत पता है कि अगले ब्लॉक में कोड केवल तभी निष्पादित होगा यदि पिछले एक ने नहीं किया था। कोई उपद्रव कोई अव्यवस्था नहीं। यदि यह एक सादा है, तो यह निष्पादित हो सकता है या यह नहीं हो सकता है, भले ही पिछले एक को निष्पादित किया गया हो। अब मुझे पिछले ब्लॉक को पार्स करने के लिए कुछ मानसिक प्रयासों का खर्च करना होगा, यह ध्यान रखना चाहिए कि यह एक के साथ समाप्त होता है । मैं व्यापार तर्क को पार्स करने पर उस मानसिक प्रयास को खर्च करता हूं। returnifelseelse ififreturn
बजे एक CVn

1
मुझे पता है, यह एक छोटी सी बात है, लेकिन कम से कम मेरे लिए, else ifएक शब्दार्थ इकाई है। (यह अनिवार्य रूप से संकलक के लिए एक इकाई नहीं है, लेकिन यह ठीक है।) ...; return; } if (...नहीं करता है; अगर यह कई लाइनों में फैला हुआ है तो अकेले रहने दें। यह कुछ ऐसा है जिसे मैं वास्तव में देखने के लिए देखना चाहता हूं कि यह क्या कर रहा है, इसके बजाय इसे सीधे कीवर्ड जोड़ी को देखकर सीधे लेने में सक्षम है else if
बजे एक CVn

@ MichaelKjörling Full Ack.I खुद else ifनिर्माण को पसंद करेगा , खासकर जब से इसका जंजीर रूप एक प्रसिद्ध पैटर्न है। हालाँकि, फ़ॉर्म if(...) return ...;का कोड भी एक प्रसिद्ध पैटर्न है, इसलिए मैं इसकी पूरी तरह से निंदा नहीं करूंगा। मैं इसे वास्तव में एक मामूली मुद्दे के रूप में देखता हूं, हालांकि: दोनों मामलों में नियंत्रण प्रवाह तर्क समान है, और एक if(...) { ...; return; }सीढ़ी पर एक करीब से देखने पर मुझे पता चलेगा कि यह वास्तव में एक else ifसीढ़ी के बराबर है । मुझे एक शब्द की संरचना दिखाई देती है, मुझे इसका अर्थ पता चलता है, मुझे पता है कि यह हर जगह दोहराया जाता है, और मुझे पता है कि क्या हो रहा है।
22

जावास्क्रिप्ट / नोड.जेएस से आ रहा है, कुछ "बेल्ट और सस्पेंडर्स" कोड का उपयोग करेंगे दोनों else if और return । जैसेelse if(...) { return alert();}
user949300

1
"और याद रखें, इस सलाह के बारे में भी धार्मिक मत समझिए।" +1
शब्द जैरेड

22

यह विवादास्पद है कि क्या यह मैदान से 'बेहतर' है अगर..किसी भी मामले के लिए। लेकिन अगर आप कुछ और कोशिश करना चाहते हैं तो यह एक सामान्य तरीका है।

अपनी शर्तों को वस्तुओं में रखें और उन वस्तुओं को एक सूची में रखें

foreach(var condition in Conditions.OrderBy(i=>i.OrderToRunIn))
{
    if(condition.EvaluatesToTrue())
    {
        addAlert(condition.Alert);
        break;
    }
}

यदि हालत पर कई क्रियाओं की आवश्यकता होती है तो आप कुछ पागल पुनरावृत्ति कर सकते हैं

void RunConditionalAction(ConditionalActionSet conditions)
{
    foreach(var condition in conditions.OrderBy(i=>i.OrderToRunIn))
    {
        if(condition.EvaluatesToTrue())
        {
            RunConditionalAction(condition);
            break;
        }
    }
}

बिल्कुल हाँ। यह केवल तभी काम करता है जब आपके पास अपने तर्क के लिए एक पैटर्न हो। यदि आप एक सुपर जेनेरिक पुनरावर्ती सशर्त कार्रवाई करने का प्रयास करते हैं तो ऑब्जेक्ट के लिए सेटअप मूल रूप से जटिल होगा यदि कथन। आप अपनी नई भाषा / रूपरेखा का आविष्कार करेंगे।

लेकिन अपने उदाहरण करता है एक पैटर्न है

इस पैटर्न के लिए एक सामान्य उपयोग मामला मान्य होगा। के बजाय :

bool IsValid()
{
    if(condition1 == false)
    {
        throw new ValidationException("condition1 is wrong!");
    }
    elseif(condition2 == false)
    {
    ....

}

हो जाता है

[MustHaveCondition1]
[MustHaveCondition2]
public myObject()
{
    [MustMatchRegExCondition("xyz")]
    public string myProperty {get;set;}
    public bool IsValid()
    {
        conditions = getConditionsFromReflection()
        //loop through conditions
    }
}

27
यह केवल सूची if...elseके निर्माण में सीढ़ी को आगे बढ़ाता है Conditions। शुद्ध लाभ नकारात्मक है, क्योंकि निर्माण में Conditionsओपी कोड जितना ही कोड होगा, लेकिन जोड़ा गया अप्रत्यक्ष पठनीयता में लागत के साथ आता है। मैं निश्चित रूप से एक साफ कोडित सीढ़ी पसंद करूंगा।
सेमीस्टर

3
@cmaster हाँ मुझे लगता है कि मैंने ठीक कहा कि "" तब वस्तु के लिए सेटअप मूल रूप में जटिल होगा यदि स्टेटमेंट पाउंड
इवान

7
यह मूल से कम पठनीय है। यह पता लगाने के लिए कि वास्तव में किस स्थिति की जाँच की जा रही है, आपको कोड के किसी अन्य क्षेत्र में खुदाई करने की आवश्यकता है। यह अप्रत्यक्ष स्तर का एक अनावश्यक स्तर जोड़ता है जो कोड को समझने में कठिन बनाता है।
17 की 26

8
यदि .. और यदि .. और .. की तालिका को विधेय और कार्यों की तालिका में बदलना समझ में आता है, लेकिन केवल बहुत बड़े उदाहरणों के लिए। तालिका कुछ जटिलता और अप्रत्यक्षता को जोड़ती है, इसलिए आपको इस वैचारिक उपरि को संशोधित करने के लिए पर्याप्त प्रविष्टियों की आवश्यकता है। इसलिए, 4 विधेय / एक्शन जोड़े के लिए, सरल मूल कोड रखें, लेकिन यदि आपके पास 100 थे, तो निश्चित रूप से तालिका के साथ जाएं। क्रॉसओवर बिंदु कहीं बीच में है। @cmaster, तालिका को वैधानिक रूप से प्रारंभ किया जा सकता है, इसलिए एक विधेय / एक्शन जोड़ी को जोड़ने के लिए वृद्धिशील ओवरहेड एक पंक्ति है जो केवल उन्हें नाम देती है: बेहतर करने के लिए कठिन।
स्टीफन सी। स्टील

2
पठनीयता व्यक्तिगत नहीं है। यह प्रोग्रामिंग जनता के लिए एक कर्तव्य है। यह व्यक्तिपरक है। जो वास्तव में क्यों इस तरह के स्थानों पर आने के लिए महत्वपूर्ण है और सुनने के लिए कि सार्वजनिक जनता को इसके बारे में क्या कहना है। व्यक्तिगत रूप से मुझे यह उदाहरण अधूरा लगता है। मुझे दिखाओ कि कैसे conditionsनिर्माण किया जाता है ... एआरजी! एनोटेशन-विशेषताएँ नहीं! ईश्वर क्यों? ओ मेरी आँखें!
कैंडिड_ऑरेंज

7

return;एक शर्त के सफल होने के बाद उपयोग करने पर विचार करें , यह आपको सभी elseएस बचाता है । यदि आप return addAlert(1)उस पद्धति का रिटर्न मान रखते हैं, तो आप सीधे भी सक्षम हो सकते हैं ।


3
बेशक, यह मानता है कि ifएस की श्रृंखला के बाद और कुछ नहीं होता है ... यह एक उचित धारणा हो सकती है, और फिर फिर से नहीं हो सकती है।
एक CVn

5

मैंने इस तरह के क्लीनर को कभी-कभी निर्माण के रूप में देखा है:

switch(true) {
    case cond1(): 
        statement1; break;
    case cond2():
        statement2; break;
    case cond3():
        statement3; break;
    // .. etc
}

सही रिक्ति के साथ टर्नरी भी एक साफ विकल्प हो सकता है:

cond1() ? statement1 :
cond2() ? statement2 :
cond3() ? statement3 : (null);

मुझे लगता है कि आप जोड़ी वाली स्थिति और फ़ंक्शन के साथ एक सरणी बनाने की कोशिश कर सकते हैं और पहली शर्त पूरी होने तक उस पर पुनरावृति कर सकते हैं - जो कि जैसा कि मैं देख रहा हूं वह इवान के पहले उत्तर के बराबर होगा।


1
त्रिगुट साफ
इवान

6
@ एक टूटी हुई "गहरी पुनरावर्ती टर्नरी" को डीबग करना एक आवश्यक दर्द हो सकता है।
१५

5
यह स्क्रीन पर साफ दिखता है
इवान

उह, कौन सी भाषा caseलेबल के साथ फ़ंक्शन का उपयोग करने की अनुमति देती है ?
undercat

1
@undercat जो एक वैध ECMAScript / JavaScript afaik
zworek

1

@ इवान के जवाब के एक संस्करण के रूप में आप इस तरह की स्थितियों की एक श्रृंखला ("फ्लैट सूची" के बजाय) बना सकते हैं:

abstract class Condition {
  private static final  Condition LAST = new Condition(){
     public void alertOrPropagate(DisplayInterface display){
        // do nothing;
     }
  }
  private Condition next = Last;

  public Condition setNext(Condition next){
    this.next = next;
    return this; // fluent API
  }

  public void alertOrPropagate(DisplayInterface display){
     if(isConditionMeet()){
         display.alert(getMessage());
     } else {
       next.alertOrPropagate(display);
     }
  }
  protected abstract boolean isConditionMeet();
  protected abstract String getMessage();  
}

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

यह वह जगह है जहां यह "फ्लैट सूची" दृष्टिकोण से बेहतर है जहां आपको शर्तों को लागू करने वाले लूप में "लंघन" को लागू करना होगा।

आप बस शर्त श्रृंखला स्थापित करते हैं:

Condition c1 = new Condition1().setNext(
  new Condition2().setNext(
   new Condition3()
 )
);

और एक साधारण कॉल के साथ मूल्यांकन शुरू करें:

c1.alertOrPropagate(display);


4
मैं किसी और के लिए बात करने के लिए बहाना नहीं होगा, लेकिन, विचाराधीन कोड तुरंत पठनीय और अपने व्यवहार में स्पष्ट है, मैं होता नहीं तुरंत यह क्या करता है के रूप में स्पष्ट होना करने के लिए इस पर विचार करें।
बजे एक CVn

0

सबसे पहले, मूल कोड भयानक IMO नहीं है। यह काफी समझ में आता है और इसमें कुछ भी बुरा नहीं है।

यदि आप इसे नापसंद करते हैं, तो सूची का उपयोग करने के लिए @ इवान के विचार पर निर्माण करना लेकिन उसके कुछ अप्राकृतिक foreach breakपैटर्न को हटाना :

public class conditions
{
    private List<Condition> cList;
    private int position;

    public Condition Head
    {
        get { return cList[position];}
    }

    public bool Next()
    {
        return (position++ < cList.Count);
    }
}


while not conditions.head.check() {
  conditions.next()
}
conditions.head.alert()

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

संपादित करें: ऐसा लगता है कि यह उतना स्पष्ट नहीं है जितना मैंने सोचा था, इसलिए मुझे आगे की व्याख्या करने दें। conditionsकिसी प्रकार की एक आदेशित सूची है; headक्या वर्तमान तत्व की जांच की जा रही है - शुरुआत में यह सूची का पहला तत्व है, और हर बार next()इसे निम्नलिखित में से एक कहा जाता है; check()और alert()कर रहे हैं checkConditionX()और addAlert(X)ओ पी से।


1
(घटाया नहीं) लेकिन मैं इसका पालन नहीं कर सकता। सिर क्या है ?
बेले-सोफी

@ Belle मैंने आगे समझाने के लिए उत्तर संपादित किया। यह इवान के रूप में एक ही विचार है, लेकिन while notइसके बजाय foreach break
निको

एक शानदार विचार का शानदार विकास
इवान

0

प्रश्न में कुछ बारीकियों का अभाव है। यदि शर्तें हैं:

  • परिवर्तन के अधीन या
  • अनुप्रयोग या सिस्टम या के अन्य भागों में दोहराया जाता है
  • कुछ मामलों में संशोधित (जैसे अलग-अलग बिल्ड, परीक्षण, परिनियोजन)

या यदि सामग्री addAlertअधिक जटिल है, तो संभवतः c # में बेहतर समाधान होगा:

//in some central spot
IEnumerable<Tuple<Func<bool>, int>> Conditions = new ... {
  Tuple.Create(CheckCondition1, 1),
  Tuple.Create(CheckCondition2, 2),
  ...
}

//at the original place
var matchingCondition = Conditions.Where(c=>c.Item1()).FirstOrDefault();
if(matchingCondition != null) 
  addAlert(matchingCondition.Item2)

टुपल्स c # <8 में बहुत सुंदर नहीं हैं, लेकिन शील के लिए चुना गया है।

इस विधि के साथ, भले ही ऊपर दिए गए विकल्पों में से कोई भी लागू न हो, यह है कि संरचना सांख्यिकीय रूप से टाइप की गई है। आप गलती से नहीं कह सकते हैं, कहते हैं, एक लापता है else


0

उन मामलों में साइक्लोमैटिक जटिलता को कम करने का सबसे अच्छा तरीका है जहां आपके पास कुंजी मूल्य (यदि कथन मूल्य या कुछ मूल्य) को संग्रहीत if->then statementsकरने के लिए एक शब्दकोश या सूची (भाषा पर निर्भर) का उपयोग करना है और फिर एक मूल्य / फ़ंक्शन परिणाम है।

उदाहरण के लिए, (C #) के बजाय:

if (i > 10) { return "Two"; }
else if (i > 8) { return "Four" }
else if (i > 4) { return "Eight" }
return "Ten";  //etc etc say anything after 3 or 4 values

मैं बस कर सकता हूं

var results = new Dictionary<int, string>
{
  { 10, "Two" },
  { 8, "Four"},
  { 4, "Eight"},
  { 0, "Ten"},
}

foreach(var key in results.Keys)
{
  if (i > results[key]) return results.Values[key];
}

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

var results = new Dictionary<Func<int, bool>, Func<int, string>>
{
  { (i) => return i > 10; ,
    (i) => return i.ToString() },
  // etc
};

foreach(var key in results.Keys)
{ 
  if (key(i)) return results.Values[key](i);
}

0

मैं अंकल बॉब के क्लीन कोड सुझावों का पालन करने की कोशिश कर रहा हूं और विशेष रूप से तरीकों को छोटा रखने के लिए।

मैं अपने आप को इस तर्क को छोटा करने में असमर्थ पाता हूँ:

if (checkCondition()) {addAlert(1);}
else if (checkCondition2()) {addAlert(2);}
else if (checkCondition3()) {addAlert(3);}
else if (checkCondition4()) {addAlert(4);}

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

if (is_an_apple()) {
  addAlert(1);
}
else if (is_a_banana()) {
  addAlert(2);
}
else if (is_a_cat()) {
  addAlert(3);
}
else if (is_a_dog()) {
  addAlert(4);
}

आपका कोड सभी के ऊपर पढ़ने योग्य होना चाहिए। अंकल बॉब की कई किताबें पढ़ने के बाद, मेरा मानना ​​है कि यह वह संदेश है जिसे वह लगातार पाने की कोशिश कर रहा है।


0

मान लें कि सभी फ़ंक्शन एक ही घटक में लागू किए गए हैं, तो आप प्रवाह में कई शाखाओं से छुटकारा पाने के लिए फ़ंक्शन को कुछ स्थिति बनाए रख सकते हैं।

ईजी: checkCondition1()बन जाएगा evaluateCondition1(), जिस पर यह जांच करेगा कि क्या पिछली स्थिति पूरी हुई थी; यदि ऐसा है, तो यह पुनः प्राप्त करने के लिए कुछ मूल्य को कैश करता है getConditionNumber()

checkCondition2()बन जाएगा evaluateCondition2(), जिस पर यह जांच करेगा कि पिछली शर्तें पूरी हुई थीं या नहीं। यदि पिछली स्थिति पूरी नहीं हुई थी, तो यह शर्त 2 परिदृश्य के लिए जाँच करता है, एक मान को पुनः प्राप्त करने के लिए कैशिंग getConditionNumber()। और इसी तरह।

clearConditions();
evaluateCondition1();
evaluateCondition2();
evaluateCondition3();
evaluateCondition4();
if (anyCondition()) { addAlert(getConditionNumber()); }

संपादित करें:

इस दृष्टिकोण से काम करने के लिए महंगी स्थितियों के लिए चेक को कैसे लागू किया जाना चाहिए।

bool evaluateCondition34() {
    if (!anyCondition() && A && B && C) {
        conditionNumber = 5693;
        return true;
    }
    return false;
}

...

bool evaluateCondition76() {
    if (!anyCondition() && !B && C && D) {
        conditionNumber = 7658;
        return true;
    }
    return false;
}

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

clearConditions();
evaluateCondition10();
evaluateCondition9();
evaluateCondition8();
evaluateCondition7();
...
evaluateCondition34();
...
evaluateCondition76();

if (anyCondition()) { addAlert(getConditionNumber()); }

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


मुझे यह सुझाव पसंद नहीं है - यह कई कार्यों के अंदर परीक्षण तर्क को छुपाता है। यह कोड को बनाए रखने के लिए कठिन बना सकता है यदि, उदाहरण के लिए, आपको ऑर्डर बदलने और # 2 से पहले # 3 करने की आवश्यकता है।
लॉरेंस

नहीं। आप जांच कर सकते हैं कि कुछ पिछली स्थिति का मूल्यांकन किया गया था या नहीं anyCondition() != false
एमर्सन कार्डसो

1
ठीक है, मैं देख रहा हूँ कि तुम क्या कर रहे हो। हालाँकि, यदि (कहते हैं) स्थितियां 2 और 3 दोनों का मूल्यांकन करती हैं true, तो ओपी नहीं चाहता कि हालत 3 का मूल्यांकन किया जाए।
लॉरेंस

मेरा मतलब है कि आप anyCondition() != falseकार्यों के भीतर जांच कर सकते हैं evaluateConditionXX()। इसे लागू करना संभव है। यदि आंतरिक स्थिति का उपयोग करने का दृष्टिकोण वांछित नहीं है, तो मैं समझता हूं, लेकिन यह तर्क कि यह काम नहीं करता है, मान्य नहीं है।
एमर्सन कार्डसो

1
हां, मेरी आपत्ति यह है कि यह परीक्षण के तर्क को अनजाने में छिपाता है, यह नहीं कि यह काम नहीं कर सकता। आपके उत्तर (पैराग्राफ 3) में, मीटिंग 1 के लिए चेक को eval ... 2 () के अंदर रखा गया है। लेकिन अगर वह 1 और 2 की स्थिति को शीर्ष स्तर पर ले जाता है (ग्राहकों की आवश्यकताओं में बदलाव के कारण, आदि), तो आपको स्थिति 1 के लिए चेक निकालने के लिए eval ... 2 () में जाना होगा, साथ ही eval में जाना होगा। ..1 () हालत के लिए एक चेक जोड़ने के लिए 2. यह काम करने के लिए बनाया जा सकता है, लेकिन यह आसानी से रखरखाव के साथ समस्याओं को जन्म दे सकता है।
लॉरेंस

0

कोई भी दो से अधिक "और" क्लॉज़ कोड के पाठक को ब्याज की एक खोजने के लिए पूरी श्रृंखला के माध्यम से जाने के लिए मजबूर करता है। एक विधि का उपयोग करें जैसे: शून्य AlertUponCondition (कंडीशन कंडीशन) {स्विच (कंडीशन) {केस Condition.Con1: ... break; मामला Condition.Con2: ... तोड़; आदि ...} जहां "स्थिति" एक उचित एनम है। यदि आवश्यक हो, तो एक बूल या मान लौटाएं। इसे इस तरह से कॉल करें: AlertOnCondition (GetCondition ());

यह वास्तव में कोई भी सरल नहीं हो सकता है, और यदि आप कुछ मामलों को पार कर लेते हैं तो यह और-और-श्रृंखला की तुलना में तेज़ है।


0

मैं आपकी विशेष स्थिति के लिए नहीं बोल सकता क्योंकि कोड विशिष्ट नहीं है, लेकिन ...

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

बहुरूपता आपके लिए बेहतर हो सकता है।

लंबे-चौड़े तरीकों वाले कोड के बारे में संदेह रखें, अगर-तब निर्माण करते हैं। आप अक्सर कुछ आभासी तरीकों के साथ वहां एक क्लास ट्री चाहते हैं।

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