If statements in a function what is the best way
如果我有一个带有大量条件的函数,那么组织它的最佳方法是什么?
我担心的是有人进入代码并理解正在发生的事情。尽管这个例子很简单,但是假设条件非常复杂。
举个例子:
1 2 3 4 5 6 7 8 | public void function(string value, string value2) { if (value == null) return; if (value2 == value) DoSomething(); } |
或
1 2 3 4 5 6 7 8 | public void function(string value, string value2) { if (value != null) { if (value2 == value) DoSomething(); } } |
或
1 2 3 4 5 | public void function(string value, string value2) { if (value != null && value2 == value) DoSomething(); } |
把这些条件组织起来,形成一种方法。
例如,替换此:
1 2 3 4 5 | if( a& & n || c && ( ! d || e ) && f > 1 && ! e < xyz ) { // good! planets are aligned. buyLotteryTicket(); } else if( ..... oh my ... ) { } |
进入这个:
1 2 3 4 5 | if( arePlanetsAligned() ) { buyLotteryTicket(); } else if( otherMethodHere() ) { somethingElse(); } |
这样,您使用的样式(1、2或3)并不重要,因为if语句将清楚地描述正在测试的条件。不需要额外的构造。
关键是要使代码更清晰和自我记录。如果您使用的是OO编程语言,那么您可以使用对象来存储状态(变量),并避免创建采用5-10个参数的方法。
这些问题类似:
消除嵌套IFS的最佳方法
有没有别的办法来代替这个超识别码
第二个链接1显示了一种更完整和复杂的方法,将恐怖的"每个人维护者"的噩梦转换成一个自我记录的代码。
它显示了如何转换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public String myFunc(SomeClass input) { Object output = null; if(input != null) { SomeClass2 obj2 = input.getSomeClass2(); if(obj2 != null) { SomeClass3 obj3 = obj2.getSomeClass3(); if(obj3 != null && !BAD_OBJECT.equals(obj3.getSomeProperty())) { SomeClass4 = obj3.getSomeClass4(); if(obj4 != null) { int myVal = obj4.getSomeValue(); if(BAD_VALUE != myVal) { String message = this.getMessage(myVal); if(MIN_VALUE <= message.length() && message.length() <= MAX_VALUE) { //now actually do stuff! message = result_of_stuff_actually_done; } } } } } } return output; } |
进入这个:
1 2 3 4 5 6 7 | if ( isValidInput() && isRuleTwoReady() && isRuleTreeDifferentOf( BAD_OBJECT ) && isRuleFourDifferentOf( BAD_VALUE ) && isMessageLengthInRenge( MIN_VALUE , MAX_VALUE ) ) { message = resultOfStuffActuallyDone(); } |
您可以查看防御编程,以确保方法功能的契约能够得到满足。
1 2 3 4 5 6 7 | public void function(string value, string value2) { if (string.IsNullOrEmpty(value1)) throw new ArgumentNullException("value1","value 1 was not set"); if (string.IsNullOrEmpty(value2)) throw new ArgumentNullException("value2","value 2 was not set"); DoSomething(); } |
我更喜欢第一种选择——快速失败更干净、更清晰、更容易阅读和理解。
我知道这不是失败,但这个概念仍然适用。我真的不喜欢嵌套的
我可以推荐Robert C.Martin的书clean code,它为编写可读和可维护的代码提供了一套很好的启发式方法。
现在,另一个选项是将条件提取到另一个私有函数中并命名它,以便它描述您的意图。它在所提供的代码中工作得不太好,因为它是通用的,但看起来像:
1 2 3 4 5 6 7 8 9 10 11 12 | public void function(string value, string value2) { if (valuesAreValidAndEqual(value, value2)) { DoSomething(); } } private void valuesAreValidAndEqual(string value, string value2) { return value != null && value2 == value; } |
显然,如果变量名和函数名与您的域相关,这将更有用。
把这些东西重构成它自己的函数。读一个描述性的函数名比读一堆布尔表达式要好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // leave complex conditional code out, so that we can focus on the larger problem in the function public void function(string value, string value2) { if (MyDescriptiveTestName) { DoSomething(); } } // encapsulate complex conditional code so that we can focus solely on it. private bool MyDescriptiveTestName(string value, string value2) { if (value != null && value2 == value) { return true; } return false; } |
如果你有一个有很多条件的函数,我会使用
相关堆栈溢出项目:
- "else if"是否比"switch()case"更快?
- 何时使用if else if else切换开关柜,反之亦然
清晰往往是难以判断的品质。当你写一段代码时,你所清楚的事情可能会完全被其他人所蒙蔽,甚至在足够长的时间过后你自己也会如此。
以下是我在构建带有许多条件检查的函数时的个人经验规则:
在一个函数中有这么多语句,这是一个迹象,表明该函数应该划分为较小的语句。
没有最好的方法来放置if语句,我认为答案是主观的。
我的偏好是第二种选择。就我个人而言,当我阅读这样的代码时,我会记住进入每个嵌套级别的条件。在第一个示例中,我可能会忘记第一个条件(value==null为false)继续保持不变。第三个也不错,但我更喜欢第二个。
事实上,您提前考虑代码的可读性是其中的一半。
至于你的例子中哪一个可读性最好,这是非常主观的。
我对所给例子的看法:
- 就个人而言,我认为第一个例子最容易跟随。
- 最小化嵌套级别和/或条件数通常增强可读性。
- 有些人会反对多元化方法的退出点(如例1),但我认为当方法变得很长。它不是真的如果你只是检查输入并快速失败。
我喜欢第三种选择,但这取决于语言。您假设在第三个语句中,语句的第一部分将失败,而不是执行第二部分。这取决于语言。我知道大多数基于C的语言都会这样做,但是因为您没有指定一种潜在的问题。可能有一个我不知道,没有短路的概念。