2008-08-08 14 views
28

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

क्या कोई अन्य विधियां हैं जिन्हें आपने पाया है जो मेरे और किसी और के लिए उपयोग की जा सकती हैं जो एक ही समस्या को प्रभावित करती है?

उदाहरण के लिए, एक लाइन में सब:

if (var1 = true && var2 = true && var2 = true && var3 = true && var4 = true && var5 = true && var6 = true) 
{ 

उदाहरण, बहु लाइन:

if (var1 = true && var2 = true && var2 = true 
&& var3 = true && var4 = true && var5 = true 
&& var6 = true) 
{ 

उदाहरण-नेस्टेड:

if (var1 = true && var2 = true && var2 = true && var3 = true) 
{ 
    if (var4 = true && var5 = true && var6 = true) 
    { 

उत्तर

61

अलग कई बूलियन्स में हालत और फिर शर्त के रूप में एक मास्टर बूलियन का उपयोग करें।

bool isOpaque = object.Alpha == 1.0f; 
bool isDrawable = object.CanDraw && object.Layer == currentLayer; 
bool isHidden = hideList.Find(object); 

bool isVisible = isOpaque && isDrawable && ! isHidden; 

if(isVisible) 
{ 
    // ... 
} 

अभी तक बेहतर:

public bool IsVisible { 
    get 
    { 
     bool isOpaque = object.Alpha == 1.0f; 
     bool isDrawable = object.CanDraw && object.Layer == currentLayer; 
     bool isHidden = hideList.Find(object); 

     return isOpaque && isDrawable && ! isHidden; 
    } 
} 

void Draw() 
{ 
    if(IsVisible) 
    { 
     // ... 
    } 
} 

करें कि आप अपने चर नाम है कि वास्तव में समारोह इरादा बजाय संकेत मिलता देते हैं। यह डेवलपर को आपके कोड को बनाए रखने में बहुत मदद करेगा ... यह आप हो सकता है!

+0

सरल, आसानी से करते हैं, और प्रभावी बढ़ाता है के साथ गलत कुछ भी नहीं है। –

5

पहले, मैं सभी को दूर करता हूँ == true भागों, जो इसे 50% कम कर देगा;)

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

कभी-कभी मैं बूलियन अभिव्यक्तियों को थोड़ा सा सरल बनाने के लिए De-Morgan's laws का उपयोग करता हूं।

1

मैं अलग बूलियन मूल्यों का सहारा:

Bool cond1 == (var1 && var2); 
Bool cond2 == (var3 && var4); 

if (cond1 && cond2) {} 
3

मैं एक टैब के साथ अपने अगर बयान में लोगों और संपादकों या तो प्रत्येक शर्त इंडेंट का एक बहुत देखा है, या यह मिलान खुला कोष्ठक के साथ:

if (var1 == true 
    && var2 == true 
    && var3 == true 
    ) { 
    /* do something.. */ 
} 

मैं आमतौर पर पिछले शर्त के रूप में एक ही लाइन पर करीब कोष्ठक डाल:

if (var1 == true 
    && var2 == true 
    && var3 == true) { 
    /* do something.. */ 
} 

लेकिन मुझे नहीं लगता कि यह काफी साफ है।

6

मैं अक्सर इन घटक बूलियन चर में विभाजित होगी:

bool orderValid = orderDate < DateTime.Now && orderStatus != Status.Canceled; 
bool custValid = customerBalance == 0 && customerName != "Mike"; 
if (orderValid && custValid) 
{ 
... 
2

खैर, सबसे पहले, क्यों नहीं:

अगर (var1 & & var2 & & var2 & & var3 & & var4 & & var5 & & var6) {
...

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

यह बेहतर नहीं है, लेकिन मैंने पहले क्या किया है: (निम्न विधि शॉर्ट सर्किटिंग बूलियन परीक्षण को रोकती है, सभी परीक्षण तब भी चलते हैं जब पहले झूठा होता है। अनुशंसित पैटर्न नहीं जब तक आपको पता न हो कि आपको आवश्यकता है लौटने से पहले सभी कोड को हमेशा निष्पादित करने के लिए - मेरी गलती को देखने के लिए ptomato के लिए धन्यवाद!)

बूलियन ठीक = cond1;
ठीक & = cond2;
ठीक & = cond3;
ठीक & = cond4;
ठीक & = cond5;
ठीक & = cond6;

कौन सा रूप में ही है: (समान नहीं, टिप्पणी ऊपर देखें!)

ठीक = (cond1 & & cond2 & & cond3 & & cond4 & & cond5 & & cond6) ;

+0

यह वही नहीं है यदि '&&' ऑपरेटर शॉर्ट सर्किटिंग है। – ptomato

+0

वाह। मुझे यह पता होना चाहिए था। मेरे पहले चेहरे पर मेरा पहला चेहरा ;-) –

0

मैं स्तर से उन्हें नीचे तोड़ने के लिए पसंद है, तो मैं आप इस तरह उदाहरण स्वरूप चाहते हैं:

if (var1 = true 
&& var2 = true 
&& var2 = true 
&& var3 = true 
&& var4 = true 
&& var5 = true 
&& var6 = true){ 

यह आसान है आप और अधिक नेस्टिंग है जब, इस तरह (स्पष्ट रूप से वास्तविक स्थिति अधिक होगा की तुलना में सब कुछ के लिए "सच =") दिलचस्प:

if ((var1 = true && var2 = true) 
&& ((var2 = true && var3 = true) 
    && (var4 = true && var5 = true)) 
&& (var6 = true)){ 
4

चेक बाहर Implementation Patterns केंट बैक द्वारा। एक विशेष पैटर्न है जिसके बारे में मैं सोच रहा हूं जो इस स्थिति में मदद कर सकता है ... इसे "गार्ड" कहा जाता है। कई स्थितियों के बजाय, आप उन्हें एक गार्ड में तोड़ सकते हैं, जो यह स्पष्ट करता है कि किसी विधि में प्रतिकूल परिस्थितियां कौन सी हैं।

उदाहरण के लिए, यदि आप एक विधि है कि कुछ करता है, लेकिन कुछ शर्तों जहां यह कुछ ऐसा नहीं करना चाहिए, न कि कर रहे हैं:

public void doSomething() { 
    if (!condition1) { 
     return; 
    } 

    if (!condition2) { 
     return; 
    } 

    if (!condition3) { 
     return; 
    } 

    if (!condition4) { 
     return; 
    } 

    // do something 
} 
:

public void doSomething() { 
    if (condition1 && condition2 && condition3 && condition4) { 
     // do something 
    } 
} 

आप इसे करने के लिए बदल सकता है

यह थोड़ा और वर्बोज़ है, लेकिन बहुत अधिक पठनीय है, खासकर जब आप अजीब घोंसले शुरू करते हैं, तो गार्ड मदद कर सकता है (विधियों को निकालने के साथ संयुक्त)।

मैं उस पुस्तक को अत्यधिक अनुशंसा करता हूं।

+0

'फास्ट रिटर्न' 'तीर-सिर' विरोधी पैटर्न भी मारता है :) –

+0

मैं असहमत हूं कि ये गार्ड इसे पढ़ने में आसान बनाते हैं। "जटिल" स्थिति पर एक टिप्पणी बेहतर होगी। –

12

मुझे आश्चर्य है कि किसी को अभी तक यह नहीं मिला है।

http://www.refactoring.com/catalog/decomposeConditional.html

+3

मुझे सशर्त विघटन करना पसंद नहीं है, क्योंकि यह कोड संरचना को एक-ऑफ फ़ंक्शंस के साथ प्रदूषित करता है जो पुन: प्रयोज्य नहीं होते हैं।मैं संबंधित चेक के प्रत्येक "समूह" के लिए टिप्पणियों के साथ एक बड़ा IF कथन होगा। –

7

यहां संबोधित करने के लिए दो मुद्दों कर रहे हैं: एक रिफैक्टरिंग इस प्रकार की समस्या के लिए विशेष रूप नहीं है पठनीयता और understandability

"पठनीयता" समाधान एक शैली मुद्दा है और इस तरह के रूप व्याख्या के लिए खुला है ।

if (var1 == true && // Explanation of the check 
    var2 == true && // Explanation of the check 
    var3 == true && // Explanation of the check 
    var4 == true && // Explanation of the check 
    var5 == true && // Explanation of the check 
    var6 == true) // Explanation of the check 
    { } 

या इस: मेरी प्राथमिकता यह है

if (var1 && // Explanation of the check 
    var2 && // Explanation of the check 
    var3 && // Explanation of the check 
    var4 && // Explanation of the check 
    var5 && // Explanation of the check 
    var6) // Explanation of the check 
    { } 

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

/// <Summary> 
/// Tests whether all the conditions are appropriately met 
/// </Summary> 
private bool AreAllConditionsMet (
    bool var1, 
    bool var2, 
    bool var3, 
    bool var4, 
    bool var5, 
    bool var6) 
{ 
    return (
     var1 && // Explanation of the check 
     var2 && // Explanation of the check 
     var3 && // Explanation of the check 
     var4 && // Explanation of the check 
     var5 && // Explanation of the check 
     var6); // Explanation of the check 
} 

private void SomeMethod() 
{ 
    // Do some stuff (including declare the required variables) 
    if (AreAllConditionsMet (var1, var2, var3, var4, var5, var6)) 
    { 
     // Do something 
    } 
} 

, परीक्षण तर्क की वास्तविक जटिलता छिपा है, लेकिन अर्थ अर्थ मनुष्य में समझने के लिए संरक्षित है एक उच्च स्तर। यदि डेवलपर को वास्तव में विवरणों को समझने की आवश्यकता है, तो AreAllConditionsMet विधि की जांच की जा सकती है।

यह औपचारिक रूप से मुझे लगता है कि "विघटनशील सशर्त" रिफैक्टरिंग पैटर्न के रूप में जाना जाता है। Resharper या रिफैक्टर प्रो जैसे उपकरण! इस प्रकार के रिफैक्टरिंग को आसान बना सकते हैं!

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

>>> L = [True, True, True, False, True] 
>>> all(L) # True, only if all elements of L are True. 
False 
>>> any(L) # True, if any elements of L are True. 
True 

वहाँ है:

0

आप अजगर में प्रोग्रामिंग कर रहे हैं तो, इसके साथ में निर्मित all() समारोह अपने चर की सूची पर लागू (मैं बस यहाँ बूलियन शाब्दिक इस्तेमाल करेंगे) एक चिंच आपकी भाषा में कोई संबंधित फ़ंक्शन (सी #? जावा?)। यदि ऐसा है, तो यह संभवतः सबसे साफ दृष्टिकोण है।

-2

यदि आप करते हैं इस:

if (var1 == true) { 
    if (var2 == true) { 
     if (var3 == true) { 
      ... 
     } 
    } 
} 

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

+3

यह शायद इस प्रश्न का सबसे बुरा समाधान है। –

+1

क्षैतिज स्क्रॉल बार - सक्रिय करें !!! 11eleven –

0

मैकडोवेल,

आप सही है कि अभिव्यक्ति के दोनों पक्षों का मूल्यांकन जब एकल '&' ऑपरेटर का उपयोग कर रहे हैं। हालांकि, '& &' ऑपरेटर (कम से कम सी # में) का उपयोग करते समय झूठी वापसी के लिए पहली अभिव्यक्ति अंतिम अभिव्यक्ति का मूल्यांकन किया जाता है। यह फोर स्टेटमेंट से पहले विकास को किसी भी अन्य तरीके के रूप में उतना ही अच्छा बनाता है।

1

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

0

@tweakt

यह कोई बेहतर है, लेकिन क्या मैं पहले कर चुके हैं:

बूलियन ठीक = cond1; ठीक & = cond2; ठीक & = cond3; ठीक & = cond4; ठीक & = cond5; ठीक & = cond6;

कौन सा रूप में ही है:

ठीक = (cond1 & & cond2 & & cond3 & & cond4 & & cond5 & & cond6);

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

पठनीयता के लिए, मैं व्यक्तिगत रूप से ऊपर माइक स्टोन के प्रस्ताव को प्राथमिकता देता हूं। शुरुआती रूप से सक्षम होने के सभी कम्प्यूटेशनल फायदों को प्रतिबिंबित करना और संरक्षित करना आसान है। आप फ़ंक्शन में एक ही तकनीक इनलाइन भी कर सकते हैं यदि यह आपके कोड के संगठन को आपके अन्य फ़ंक्शन से सशर्त मूल्यांकन को स्थानांतरित करने के लिए भ्रमित कर देगा। यह थोड़ा घटिया है, लेकिन आप हमेशा की तरह कुछ कर सकते हैं:

do { 
    if (!cond1) 
     break; 
    if (!cond2) 
     break; 
    if (!cond3) 
     break; 
    ... 
    DoSomething(); 
} while (false); 

जबकि (गलत) तरह का घटिया है। मेरी इच्छा है कि भाषाओं में "एक बार" या कुछ ऐसा कहा जा सके जिसे आप आसानी से तोड़ सकते हैं।

+0

यह मूल कोड से बेहतर नहीं है। –

2

फ़ैक्टर और भविष्यवाणियों को देखने का प्रयास करें। Apache Commons प्रोजेक्ट में ऑब्जेक्ट्स में सशर्त तर्क को समाहित करने की अनुमति देने के लिए ऑब्जेक्ट्स का एक बड़ा सेट है। उनके उपयोग का उदाहरण O'reilly here पर उपलब्ध है। कोड उदाहरण के अंश:

import org.apache.commons.collections.ClosureUtils; 
import org.apache.commons.collections.CollectionUtils; 
import org.apache.commons.collections.functors.NOPClosure; 

Map predicateMap = new HashMap(); 

predicateMap.put(isHonorRoll, addToHonorRoll); 
predicateMap.put(isProblem, flagForAttention); 
predicateMap.put(null, ClosureUtils.nopClosure()); 

Closure processStudents = 
    ClosureUtils.switchClosure(predicateMap); 

CollectionUtils.forAllDo(allStudents, processStudents); 

अब उन सभी isHonorRoll विधेय के विवरण और उन्हें मूल्यांकन करने के लिए प्रयोग किया जाता है बंद:

import org.apache.commons.collections.Closure; 
import org.apache.commons.collections.Predicate; 

// Anonymous Predicate that decides if a student 
// has made the honor roll. 
Predicate isHonorRoll = new Predicate() { 
    public boolean evaluate(Object object) { 
    Student s = (Student) object; 

    return((s.getGrade().equals("A")) || 
      (s.getGrade().equals("B") && 
       s.getAttendance() == PERFECT)); 
    } 
}; 

// Anonymous Predicate that decides if a student 
// has a problem. 
Predicate isProblem = new Predicate() { 
    public boolean evaluate(Object object) { 
    Student s = (Student) object; 

    return ((s.getGrade().equals("D") || 
       s.getGrade().equals("F")) || 
      s.getStatus() == SUSPENDED); 
    } 
}; 

// Anonymous Closure that adds a student to the 
// honor roll 
Closure addToHonorRoll = new Closure() { 
    public void execute(Object object) { 
    Student s = (Student) object; 

    // Add an award to student record 
    s.addAward("honor roll", 2005); 
    Database.saveStudent(s); 
    } 
}; 

// Anonymous Closure flags a student for attention 
Closure flagForAttention = new Closure() { 
    public void execute(Object object) { 
    Student s = (Student) object; 

    // Flag student for special attention 
    s.addNote("talk to student", 2005); 
    s.addNote("meeting with parents", 2005); 
    Database.saveStudent(s); 
    } 
}; 
+0

अच्छा! मेथिंक के साथ डाउनलोड और खेलने के लिए एक। – toolkit

0

मैं वर्णनात्मक चर में प्रत्येक शर्त तोड़ने के लिए पसंद करते हैं।

bool isVar1Valid, isVar2Valid, isVar3Valid, isVar4Valid; 
isVar1Valid = (var1 == 1) 
isVar2Valid = (var2.Count >= 2) 
isVar3Valid = (var3 != null) 
isVar4Valid = (var4 != null && var4.IsEmpty() == false) 
if (isVar1Valid && isVar2Valid && isVar3Valid && isVar4Valid) { 
    //do code 
} 
+0

व्यक्तिगत बूल बनाने में क्या बात है। साथ ही, आप प्रत्येक 'varX' से 'true' की तुलना करते हैं और इसे' isVarXValid' बूल को असाइन करते हैं, जो अनिवार्य रूप से केवल * longhand * है 'isVar1Valid = var', जो अनावश्यक है। आपके पास पहले से शुरू करने के लिए बूल हैं, इसलिए क्यों नहीं 'अगर (var1 && var2 && var3 && var4) ' – dreamlax

+0

@dreamlax आप सही हैं। मैंने एक खराब उदाहरण इस्तेमाल किया। – wusher

2

स्टीव Mcconell की सलाह, Code Complete से: एक बहु-आयामी तालिका का उपयोग करें। प्रत्येक चर तालिका में एक सूचकांक के रूप में कार्य करता है, और यदि कथन एक तालिका लुकअप में बदल जाता है। उदाहरण के लिए अगर (आकार == 3 & & वजन> 70) तालिका प्रविष्टि निर्णय [आकार] [weight_group] में तब्दील हो

0

अगर मैं पर्ल में यह कर रहा था, यह मैं कैसे की जाँच करता चला सकता है।

{ 
    last unless $var1; 
    last unless $var2; 
    last unless $var3; 
    last unless $var4; 
    last unless $var5; 
    last unless $var6; 

    ... # Place Code Here 
} 

आप एक सबरूटीन पर इस का उपयोग करते हुए return साथ last के प्रत्येक उदाहरण की जगह करने की योजना है;

1

PHP जैसे चिंतनशील भाषाओं में, आप उपयोग कर सकते हैं चर-चर:

$vars = array('var1', 'var2', ... etc.); 
foreach ($vars as $v) 
    if ($$v == true) { 
     // do something 
     break; 
    } 
0
if ( (condition_A) 
     && (condition_B) 
     && (condition_C) 
     && (condition_D) 
     && (condition_E) 
     && (condition_F) 
     ) 
    { 
     ... 
    } 

रूप

के विपरीत

if (condition_A) { 
     if (condition_B) { 
      if (condition_C) { 
      if (condition_D) { 
       if (condition_E) { 
        if (condition_F) { 
         ... 
        } 
       } 
      } 
      } 
     } 
    } 

और

if ( ( (condition_A) 
      && (condition_B) 
      ) 
     || ( (condition_C) 
      && (condition_D) 
      ) 
     || ( (condition_E) 
      && (condition_F) 
      ) 
     ) 
    { 
     do_this_same_thing(); 
    } 

करने का विरोध किया

if (condition_A && condition_B) { 
     do_this_same_thing(); 
    } 
    if (condition_C && (condition_D) { 
     do_this_same_thing(); 
    } 
    if (condition_E && condition_F) { 
     do_this_same_thing(); 
    } 

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

खुले/करीबी ब्रेसिज़ के उसी इंडेंट स्तर पर वर्टिकल संरेखण {}, खुले बंद कोष्ठक(), बाईं ओर ब्रांड्स और ऑपरेटर के साथ सशर्त अभिव्यक्ति एक बहुत ही उपयोगी अभ्यास है, जो कोड की पठनीयता और स्पष्टता को काफी हद तक बढ़ाता है संभावित रूप से एक पंक्ति पर जाम करने के लिए विरोध किया जा सकता है, सैन्स लंबवत संरेखण, रिक्त स्थान या कंस्ट्रैसिस

ऑपरेटर प्राथमिकता नियम मुश्किल हैं, उदाहरण के लिए & & की तुलना में अधिक प्राथमिकता है ||, लेकिन | पूर्वता से & &

तो, ...

if (expr_A & expr_B || expr_C | expr_D & expr_E || expr_E && expr_F & expr_G || expr_H { 
    } 

मात्र मनुष्य पढ़ सकते हैं और अनुचित तरीके से मूल्यांकन करने के लिए के लिए एक बहुत आसान एकाधिक सशर्त अभिव्यक्ति है।

if ( ( (expr_A) 
      & (expr_B) 
      ) 
     || ( (expr_C) 
      | ( (expr_D) 
       & (expr_E) 
      ) 
      ) 
     || ( (expr_E) 
      && ( (expr_F) 
       & (expr_G) 
       ) 
      ) 
     || (expr_H) 
     ) 
    { 
    } 

क्षैतिज स्थान (linefeeds), ऊर्ध्वाधर संरेखण, या स्पष्ट कोष्टक अभिव्यक्ति मूल्यांकन मार्गदर्शक है, जो सभी पठनीयता और स्पष्टता

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