Help refactoring this C# function
我编写的函数如下:
1 2 3 4 5 6 7 8 9 10 | bool IsDry(bool isRaining, bool isWithUmbrella) { if (isRaining) { if (isWithUmbrella) return true; else return false; } else return true; } |
我需要检查一下,如果下雨的话,那么这个人需要带把雨伞来保持干燥(不要笑,这只是一个例子,我们的实际业务规则比这更严重)。
我如何重构这个,因为现在它看起来很笨拙。
谢谢你的帮助,伙计们!=)
您试图执行的业务规则是:
1 | P IMPLIES Q |
这在逻辑上等同于:
1 | (NOT P) OR Q |
因此,您可以简单地写:
1 2 3 | bool IsDry(bool isRaining, bool isWithUmbrella) { return !isRaining || isWithUmbrella; } |
消极思考
根据谓词的不同,先从否定的角度考虑也可能更简单。
1 | NOT (P IMPLIES Q) |
我们现在用上述身份进行替换:
1 | NOT ((NOT P) OR Q) |
现在我们可以应用德莫根定律:
1 | P AND (NOT Q) |
既然这是否定的,我们必须否定它才能回到肯定的状态。一开始,双重否定似乎令人困惑,但回到这个例子,我们有:
1 2 3 4 | bool IsDry(bool isRaining, bool isWithUmbrella) { bool isWet = (isRaining && !isWithUmbrella); return !isWet; } |
附加提示
下面是一些常见的
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 33 | BEFORE | AFTER ________________________________________|________________________________________ | if (condition == true) ... | if (condition) ... ________________________________________|________________________________________ | if (condition == false) ... | if (!condition) ... ________________________________________|________________________________________ | if (condition) { | return condition; return true; | } else { | return false; | } | ________________________________________|________________________________________ | if (condition1) { | return (condition1 && condition2 if (condition2) { | && condition3); if (condition3) { | return true; | } else { | return false; | } | } else { | return false; | } | } else { | return false; | } | ________________________________________|________________________________________ | return (condition1 && !condition2) || | return condition1 != condition2; (condition2 && !condition1); | // or condition1 ^ condition2; |
注意,c中的预定义
- "还是"运算符?
- 和_或运算符之间的差异是什么?
- 关于C短路评估的最佳实践是什么?
- 短路声明评估-是否有保证?〔C〕
- 何时使用
^ 运算符
1 2 3 4 | bool IsDry(bool isRaining, bool isWithUmbrella) { return (!isRaining || isWithUmbrella); } |
1 2 3 4 | bool IsDry(bool isRaining, bool isWithUmbrella) { return !isRaining || isWithUmbrella; } |
我通常采用的方法是连续改进。例如,先消除内部,否则:
1 2 3 4 5 6 | bool IsDry(bool isRaining, bool isWithUmbrella) { if (isRaining) return isWithUmbrella; else return true; } |
然后折叠if
1 2 3 | bool IsDry(bool isRaining, bool isWithUmbrella) { return isRaining ? isWithUmbrella : true; } |
这是一张真理表:
1 2 3 4 5 | isRaining isWithUmbrella isWet isDry true true false true true false true false false true false true false false false true |
有一个答案可能是:
1 2 | var isWet = isRaining && !isWithUmbrella; return !isWet; |
How can I refactor this
进行单元测试。
说真的。有两个布尔输入,所以您只需要四个单元测试就可以完全覆盖这个方法。
然后,在已经有了完整的分支覆盖的情况下,您可以随意使用实现。尝试一些看似正确的东西(我发现在本例中编写一个真值表非常有帮助),并且测试将告诉您是否有错误的细节。
作为进一步的好处,您可以永远保留测试,作为方法实际功能的文档。如果您选择了一个聪明的实现,比如漂亮的布尔表达式,这就特别有用了——如果您试图跟踪流程,那么您可以查看测试,然后看到:"哦,我明白了——如果我通过了这个和这个,我就得到了这个。"
首先从"else return…;"语句中删除"else",这样可以得到:
1 2 3 4 5 6 | if (isRaining) { if (isWithUmbrella) return true; return false; } return true; |
有点逻辑性……
1 2 3 4 5 6 7 | if (isRaining) { // return (isWithUmbrella) ? // true : // false; return isWithUmbrella; } return true; |
然后,您可以快速地将其放入一个简单的返回语句中…
1 2 3 | //return (isRaining) ? isWithUmbrella : true; //return (!isRaining) ? true : isWithUmbrella; return (!isRaining) || isWithUmbrella; |
只需单击六次,resharper就可以将代码简化为一行。
前三次单击将变形
1 2 3 4 | if (isWithUmbrella) return true; else return false; |
进入之内
1 | return isWithUmbrella; |
接下来的三次点击变了
1 2 3 4 5 6 | if (isRaining) { return isWithUmbrella; } else return true; |
进入之内
1 | return !isRaining || isWithUmbrella; |
瞧,你完了。
1 2 3 | bool IsDry(bool isRaining, bool isWithUmbrella) { return isRaining ? isWithUmbrella : true; } |
很明显
bool不下雨还带伞
-)