【问题标题】:Help refactoring this C# function帮助重构这个 C# 函数
【发布时间】:2011-03-29 20:10:57
【问题描述】:

我编写了如下所示的函数:

bool IsDry(bool isRaining, bool isWithUmbrella) {
    if (isRaining) {
        if (isWithUmbrella)
            return true;
        else
            return false;
    }
    else
        return true;
}

我要检查一下,如果下雨了,那人需要带伞以保持干燥(别笑,这只是一个例子,我们实际的业务规则比这更严重)。

我该如何重构它,因为现在它看起来很笨拙。

谢谢你们的帮助,伙计们! =)

【问题讨论】:

  • 虽然您的代码比较冗长,但我会提醒您不要在一行中编写包含两个以上变量的逻辑表达式。随着单行逻辑表达式变得越来越复杂,重构它们变得越来越容易出错,因为它们的可读性较差。例如,尝试添加 isIndoors 作为另一个变量。请注意,单线对于人类来说变得更难在飞行中进行解析。重构时请记住这一点 - 简洁并不意味着可读性。
  • 哎呀,旧的if(isTrue) return true; else return false; 反模式!

标签: c#


【解决方案1】:

看起来您要执行的业务规则是:

P IMPLIES Q

这在逻辑上等价于:

(NOT P) OR Q

因此,您可以简单地写:

bool IsDry(bool isRaining, bool isWithUmbrella) {
    return !isRaining || isWithUmbrella;
}

关于(不)消极思考

根据谓词的不同,首先考虑它的否定也可能更简单。

NOT (P IMPLIES Q)

我们现在替换上面的身份:

NOT ((NOT P) OR Q)

现在我们可以申请DeMorgan's Law:

P AND (NOT Q)

既然这是否定,我们必须否定它才能回到积极的状态。双重否定起初可能看起来令人困惑,但回到这个例子,我们有:

bool IsDry(bool isRaining, bool isWithUmbrella) {
    bool isWet = (isRaining && !isWithUmbrella);
    return !isWet;
}

其他提示

以下是一些常见的boolean表达式重写示例:

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# 中预定义的 ^exclusive-or operator,即使对于整数类型也是如此(即它不是指数运算符)。预定义的&&|| 是执行“短路”评估的conditional logical operators

另见

【讨论】:

  • +1。除此之外,!(isRaining && !isWithUmbrella) 等同于 DeMorgan 的 (!isRaining || isWithUmbrella)
  • 可能会帮助您获得答案票。如果你解释说 p 意味着 q 是离散数学......哦 55 票没关系:)
  • 天哪,可惜 OP 未注册。您应该再获得一枚大师徽章!
【解决方案2】:
bool IsDry(bool isRaining, bool isWithUmbrella) 
{
    return (!isRaining || isWithUmbrella);
}

【讨论】:

  • @Mitch 感谢那次投票,我想我在代表系统上发现了一个潜在的错误。现在在 meta 上发帖。
【解决方案3】:
bool IsDry(bool isRaining, bool isWithUmbrella)
{
    return !isRaining || isWithUmbrella;
}

【讨论】:

  • @Null,这是一场人气竞赛你不知道吗! +1 给你 Null。
【解决方案4】:

这是一个真值表:

isRaining    isWithUmbrella    isWet    isDry 
true         true              false    true
true         false             true     false
false        true              false    true
false        false             false    true

一些答案​​可能是:

var isWet = isRaining && !isWithUmbrella;
return !isWet;

【讨论】:

  • 为什么不直接:return (!(isRaining && !isWithUmbrella));
  • 我试图通过为内部布尔表达式赋予明确的含义来显示意图。希望它能让后来出现 isAlreadyWetAnyway 标志的人更容易将其放在正确的位置。
【解决方案5】:

我通常采取的方法是逐次细化。例如首先消除内部if-else:

bool IsDry(bool isRaining, bool isWithUmbrella) {
    if (isRaining)
        return isWithUmbrella;
    else
        return true;
}

然后折叠 if

bool IsDry(bool isRaining, bool isWithUmbrella) {
    return isRaining ? isWithUmbrella : true;
}

【讨论】:

    【解决方案6】:

    我该如何重构这个

    带有单元测试。

    说真的。有两个布尔输入,因此您只需要四个单元测试即可完全覆盖此方法。

    然后,有了完整的分支覆盖,您就可以尝试实现。尝试一些看起来正确的事情(我发现在这种情况下编写真值表很有帮助),测试会告诉你是否有细节错误。

    另外一个好处是,您可以永久保留测试,作为该方法实际作用的文档。如果您选择一个聪明的实现,例如花哨的布尔表达式,这将特别有用——如果您正在挠头试图遵循流程,您可以只查看测试并看到,“哦,我明白了——如果我通过这个和这个,我明白了。”

    【讨论】:

    • +1!这也将从调用者的角度显示用法,这有助于设计。 if (IsDry(true, false)) 在客户端代码中可能难以解释 - 布尔值代表什么?也许这可能是具有 IsRaining 和 HasUmbrella 属性的类的实例方法。
    【解决方案7】:
    bool IsDry(bool isRaining, bool isWithUmbrella) {
     return isRaining ? isWithUmbrella : true;
    }
    

    【讨论】:

      【解决方案8】:

      首先从“else return ...;”中删除“else”陈述,所以你得到:

      if (isRaining) {
          if (isWithUmbrella)
              return true;
          return false;
      }
      return true;
      

      有点逻辑工作..

      if (isRaining) {
      //    return (isWithUmbrella) ?
      //        true :
      //        false;
          return isWithUmbrella;
      }
      return true;
      

      那么,你可以快速将其放入一个简单的return语句中……

      //return (isRaining) ? isWithUmbrella : true;
      //return (!isRaining) ? true : isWithUmbrella;
      return (!isRaining) || isWithUmbrella;
      

      【讨论】:

        【解决方案9】:

        只需点击六次ReSharper 即可将您的代码简化为一行。

        前三个点击会变形

         if (isWithUmbrella)
                            return true;
                        else
                            return false;
        

        进入

        return isWithUmbrella;
        

        接下来的三下点击改变

            if (isRaining)
            {
                return isWithUmbrella;
            }
            else
                return true;
        

        进入

            return !isRaining || isWithUmbrella;
        

        瞧,你完成了。

        【讨论】:

        • 如果您解释了为什么 ReSharper 会有所帮助,此答案可能会很有用。
        • 我已经添加了解释。感谢您的反馈。
        【解决方案10】:

        很明显

        bool IsNotRaining { return isWithUmbrella }

        :-)

        【讨论】:

        • 开发软件而没有幽默感是一定的痛苦秘诀
        猜你喜欢
        • 1970-01-01
        • 2019-08-11
        • 1970-01-01
        • 2023-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-09
        相关资源
        最近更新 更多