c – DRY if语句
我有一个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语句更好的设计? 编辑:实现我的示例代码过于简单化.这里有一些我真正的代码,希望能更好地解释这个问题(虽然它更麻烦): 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,result)) return result; } else { if (diamondsOnly.back().value > clubsOnly.back().value) { if (passHighCards(player.hand,result)) return result; if (passHighCards(player.hand,result)) return result; } else { if (passHighCards(player.hand,result)) return result; } } } else if (!diamondsOnly.empty()) { if (passHighCards(player.hand,result)) return result; } else if (!clubsOnly.empty()) { if (passHighCards(player.hand,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. 简化逻辑 接下来我们想简化决策逻辑. 选项: > Sentinels:复杂的部分原因在于,在某些情况下,您需要取消引用其中一个容器中的最后一张卡,如果容器为空,则无法取消.有时候值得考虑在容器中添加一个标记,这样你就不需要测试空壳了 – 你可以保证它永远不会空着.这可能是可行的,也可能是不可行的.您需要使处理容器的所有其他代码了解哨兵. 把它们放在一起: // 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,result)) return result; } 这假设getHighCards处理可能为空的容器作为输入. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |