干燥 if 语句

2024-03-19

我有一个 C++ 程序,在许多不同的 .cpp 文件中,我执行如下操作:

if (!thing1.empty() && !thing2.empty())
{
    if (thing1.property < thing2.property)
        return func1();
    else if (thing2.property < thing1.property)
        return func2();
    else
        return func3();
}
else if (!thing1.empty())
{
    return func1();
}
else if (!thing2.empty())
{
    return func2();
}
else
{
   return func4();
}

如果 thing1 大于 thing2,我尝试以一种方式执行 func,如果情况相反,则向后执行 func,但如果不存在,那么我只对那一半执行 func。如果两者都不存在,我会做一些完全不同的事情。每次我使用此模式时,属性、函数和返回类型都不同。对于我想要做的事情,有比这种丑陋的混乱的嵌套 if 语句更好的设计吗?

EDIT:意识到我的示例代码过于简单化。这是我的一些真实代码,希望能更好地解释问题(尽管它更混乱):

if (!diamondsOnly.empty() && !clubsOnly.empty())
{
    if (diamondsOnly.size() < clubsOnly.size())
    {
        if (passHighCards(player.hand, getHighCards(Card::DIAMONDS), result))
            return result;
        if (passHighCards(player.hand, getHighCards(Card::CLUBS), result))
            return result;
    }
    else if (clubsOnly.size() < diamondsOnly.size())
    {
        if (passHighCards(player.hand, getHighCards(Card::CLUBS), result))
            return result;
        if (passHighCards(player.hand, getHighCards(Card::DIAMONDS), result))
            return result;
    }
    else
    {
        if (diamondsOnly.back().value > clubsOnly.back().value)
        {
            if (passHighCards(player.hand, getHighCards(Card::DIAMONDS), result))
                return result;
            if (passHighCards(player.hand, getHighCards(Card::CLUBS), result))
                return result;
        }
        else
        {
            if (passHighCards(player.hand, getHighCards(Card::CLUBS), result))
                return result;
            if (passHighCards(player.hand, getHighCards(Card::DIAMONDS), result))
                return result;
        }
    }
}
else if (!diamondsOnly.empty())
{
    if (passHighCards(player.hand, getHighCards(Card::DIAMONDS), result))
        return result;
}
else if (!clubsOnly.empty())
{
    if (passHighCards(player.hand, getHighCards(Card::CLUBS), result))
        return result;
}

先决定再做

看看真实的代码,我注意到的第一件事是有很多几乎相同的调用,仅变化一个常量。我将使用在复杂逻辑中设置的参数在一处进行调用。

// Decide what to do.
std::vector<Card::Suit> passOrder;
if (!diamondsOnly.empty() && !clubsOnly.empty()) {
    // .. complicated logic that adds suits to passOrder ..
}

// Do it.
for (auto suit : passOrder) {  // This is C++11 style -- alter as needed
    if (passHighCards(player.hand, getHighCards(suit), result))
        return result;
}

(如果向量总是只有一两个,那么使用向量可能有点矫枉过正,但我​​假设真正的代码可能会处理所有的花色。)

这使得它更容易阅读。程序员可以看到,您首先决定传递卡片的顺序,然后才真正传递它们。两个单独的步骤会更清晰。与将其副本分散在整个决策逻辑中相比,只有一个调用 passCards 的地方更不容易出现愚蠢的拼写错误。它还将使调试变得更容易,因为您可以在非常特定的情况下设置断点,或者您可以只在循环开头设置断点并检查 passOrder。

简化逻辑

接下来我们要简化决策逻辑。

Options:

  • Sentinels:复杂性的部分原因在于,在某些情况下,您需要取消引用其中一个容器中的最后一张卡,如果容器为空,则无法执行此操作。有时值得考虑向容器添加哨兵,这样您就不需要测试空的情况——可以保证它永远不会空。这可能可行,也可能不可行。您需要使处理容器的所有其他代码都能理解哨兵。

  • 只是例外:您可以通过选择默认顺序来消除某些条款,例如,钻石然后俱乐部,然后仅测试您需要俱乐部然后钻石的情况。

  • 使用临时对象表示:创建命名良好的临时对象,以简化您必须进行的比较,并根据这些临时对象来表达比较。请注意,将空/非空情况分解到临时变量中后,您可以通过选择适当的 SENTINEL_VALUE(例如 0 或 -1)来消除某些情况。

把它们放在一起:

// For readability.
const bool fewerClubs = clubsOnly.size() < diamondsOnly.size();
const bool sameNumber = clubsOnly.size() == diamondsOnly.size();
const int lastDiamondValue =  diamondsOnly.empty() ? -1 : diamondsOnly.back().value;
const int lastClubValue    =  clubsOnly   .empty() ? -1 : clubsOnly   .back().value;

// Decide what order to select cards for passing.
std::vector<Card::Suit> passOrder;
passOrder.push_back(Cards::DIAMONDS);  // default order
passOrder.push_back(Cards::CLUBS);

// Do we need to change the order?
if (fewerClubs || (sameNumber && lastClubValue > lastDiamondValue)) {
    // Yep, so start with the clubs instead.
    passOrder[0] = Cards::CLUBS;
    passOrder[1] = Cards::DIAMONDS;
}

// Do it.
for (auto suit : passOrder) {  // This is C++11 style -- alter as needed
    if (passHighCards(player.hand, getHighCards(suit), result))
        return result;
}

这假设 getHighCards 处理可能为空的容器作为输入。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

干燥 if 语句 的相关文章

随机推荐

  • 我怎样才能在android中重复周一、周二和周五的闹钟

    如何在 Android 中仅在周一 周二和周五重复闹钟 Intent myIntent new Intent getApplicationContext x class PendingIntent pendingIntent Pending
  • 如何在类模板之外定义嵌套成员模板?

    考虑以下类模板 template
  • 如何从字典中随机选择一个项目?

    我是一个 python 初学者 试图制作二十一点游戏 并且一直不断收到有关此代码的多个关键错误 def rank rank rank 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 Jack 10 King 10
  • 使用新的 Spring UriComponentsBuilder 进行 URL 编码

    我正在尝试使用 spring 的 UriComponentsBuilder 来生成一些用于 oauth 交互的 url 查询参数包括回调url 带空格的参数值等实体 尝试使用 UriComponentBuilder 因为 UriUtils
  • 如何创建关联矩阵

    我正在尝试创建 1 1 1 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 1 0 1 0 1 1 0 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 S 1
  • 如何将RequiredFieldValidator添加到DropDownList控件?

    我有一个DropDownList与一个绑定SqlDataSource显示数据库中的值 我无法使用RequiredFieldValidator 大多数情况下 您将其视为正在验证任何其他类型的控件 但使用所需字段验证器的 InitialValu
  • 在 Swift 中显示当前位置并更新 MKMapView 中的位置

    我正在学习如何使用新的 Swift 语言 只有 Swift 没有 Objective C 为此 我想用地图做一个简单的视图 MKMapView 我想查找并更新用户的位置 就像在 Apple 地图应用程序中一样 我尝试了这个 但什么也没发生
  • 如何从链接到 QTableView 的模型中插入和删除行

    The removeRows 通过删除选定的行来按预期工作 但有一个问题insertRows 由于某种原因 新项目不会出现在所选索引号处 是什么原因导致这个问题呢 from PyQt4 QtCore import from PyQt4 Qt
  • Matplotlib:如何设置当前图形?

    希望这是一个简单的问题 但我目前无法弄清楚 我想使用 matplotlib 显示 2 个数字 然后交互式地使用它们 我用以下方法创建数字 import matplotlib import pylab as pl f1 pl figure f
  • Heroku 零停机时间

    是否可以做类似的事情Github 零停机部署 https github com blog 517 unicorn在 Heroku 上使用 Cedar 堆栈上的 Unicorn 我不完全确定 Heroku 上的重启是如何进行的 以及我们对重启
  • 从我的本地计算机附加文件以在 cq/AEM 中发送邮件

    我正在学习 AEM 并且正在满足一个要求 其中我能够发送电子邮件 但无法添加从我的计算机浏览的附件 要求 有一个用 HTML 制作的表单 可以从其中收集信息 并且有一个浏览按钮 可以从其中上传文件 文件上传后 应立即将包含表单内容和附件的电
  • 使用 selenium webdriver 按类名和标记名查找元素

    有类和标记名 我正在编写下面的硒代码以从下面的代码中查找描述 但它不起作用 WebElement WWdescription driver findElement By className atb delivery accordions c
  • Swift:如何在“String”扩展中添加类方法

    我想在扩展中添加一个类函数 extension String class func test 我收到错误 Class methods are only allowed within classes use static to declare
  • 如何在两点之间填充数组列表?

    我有这段代码 解释 用户输入 initcores 数据和 time 数据 forces 是结果 我想用从 0 到 ttime 的值填充 x 数组 用 y 填充 initcores 到 fcores 并绘制散点图 x 与 y 我有一个问题 如
  • Latex:\bibliographystyle{abbrv} 根据外观排序引用[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我使用 Latex 的 bibliographystyle abbrv 命令作为参考 但引用的顺序并不按照它们在文档中出现的顺序 无论如何
  • MySQLi 准备好的语句返回 false

    我正在尝试使用 MySQLi 在我的数据库上运行多个查询 这是我的代码 stmt mysqli gt prepare SELECT password FROM users WHERE username LIMIT 1 stmt gt bin
  • 无法生成 qdoc 文档

    按照本指南操作http doc snapshot qt project org qdoc qdoc guide conf html http doc snapshot qt project org qdoc qdoc guide conf
  • C++比较C字符串的麻烦

    我编写了以下代码 该代码不起作用 但当我更改它时 第二个代码片段将起作用 int main int argc char argv if argv 1 i This is what does not work Do Something 但如果
  • scafford自动生成crud存储库asp.net5

    您好 我正在使用 Visual Studio 2015 我知道我们可以通过添加新的来生成 CRUD 视图控制器和操作scafford物品 但是代码生成不是很有用 似乎所有数据层都依赖于控制器 所以我的问题是 任何使用脚手架的方法都会生成代码
  • 干燥 if 语句

    我有一个 C 程序 在许多不同的 cpp 文件中 我执行如下操作 if thing1 empty thing2 empty if thing1 property lt thing2 property return func1 else if