干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(); } if(!thing1.empty()&&&!thing2.empty()) { if(thing1.property
如果1比2大,我试着用一种方法来做func,如果相反,我试着用反向的方法来做,但是如果一个不存在,我只做那一半的func。如果两者都不存在,我会做一些完全不同的事情。每次使用此模式时,属性、函数和返回类型都不同。对于我想做的事情,有没有比这种糟糕的嵌套if语句更好的设计 编辑:意识到我的示例代码过于简单。下面是我的一段真实代码,希望它能更好地解释这个问题(尽管它要复杂得多):干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(); } if(!thing1.empty()&&&!thing2.empty()) { if(thing1.property,c++,if-statement,dry,C++,If Statement,Dry,如果1比2大,我试着用一种方法来做func,如果相反,我试着用反向的方法来做,但是如果一个不存在,我只做那一半的func。如果两者都不存在,我会做一些完全不同的事情。每次使用此模式时,属性、函数和返回类型都不同。对于我想做的事情,有没有比这种糟糕的嵌套if语句更好的设计 编辑:意识到我的示例代码过于简单。下面是我的一段真实代码,希望它能更好地解释这个问题(尽管它要复杂得多): if(!diamondsOnly.empty()&&!clubsOnly.empty()) { if(diamondsO
if(!diamondsOnly.empty()&&!clubsOnly.empty())
{
if(diamondsOnly.size()clubsOnly.back().value)
{
如果(通过HighCards(player.hand,getHighCards(卡片:钻石),结果))
返回结果;
if(通过高卡(玩家手牌,获得高卡(卡::俱乐部),结果))
返回结果;
}
其他的
{
if(通过高卡(玩家手牌,获得高卡(卡::俱乐部),结果))
返回结果;
如果(通过HighCards(player.hand,getHighCards(卡片:钻石),结果))
返回结果;
}
}
}
else如果(!diamondsOnly.empty())
{
如果(通过HighCards(player.hand,getHighCards(卡片:钻石),结果))
返回结果;
}
如果(!clubsOnly.empty())
{
if(通过高卡(玩家手牌,获得高卡(卡::俱乐部),结果))
返回结果;
}
我不确定这是否是一个巨大的改进,但您可以通过以下方法稍微消除毛茸茸的感觉:
if (thing1.empty() && thing2.empty())
return func4();
else if (thing1.empty())
return func2();
else if (thing2.empty())
return func1();
else if (thing1.property < thing2.property)
return func1();
else if (thing2.property < thing1.property)
return func2();
else
return func3();
然后,当您涵盖了所有条件后,执行一个简单的循环来做正确的事情
for (int i = 0; i < 2; i++)
{
if (pass[i] != -1 && passHighCards(player.hand, getHighCards(pass[i]), result))
return result;
}
...undocumented what happens here...
for(int i=0;i<2;i++)
{
如果(通过[i]!=-1&&PasshHighCards(player.hand,getHighCards(通过[i]),结果))
返回结果;
}
…这里发生的事没有记录。。。
二是轻度不适;它出现了两次
但是,总的来说,这为您提供了一个线性的测试序列,每个测试之后都有简单的对称动作(为了一致性,这次保留了大括号,因为动作不止一行长;一致性比大括号本身的存在或不存在更重要)。当关于做什么的决定完成后,你实际上就去做了。创建一个界面,比如说IMyCompare。 使用接受IMyCompare并返回Func的方法 然后你可以在每件事情上实现整个事情 做 类似于AThing.MyCompare(其他事物) 如果每个条件中的哪个函数不是由对象的类型确定的,那么将函数数组传递给比较调用
我很想从MyCompare返回一个int,并将如何使用它的问题委托给我认为是其他问题。您可以计算所有条件并将它们发送给某个函数,该函数应该执行决策,然后返回一个代码,告诉下一步该做什么。然后,所有重复的“模式”都将位于函数内部
// return decision1 or decision2, depending on the result of comparison of properties
// Note: type is ssize_t to accommodate bool, size_t and whatever type is 'value'
int decision(ssize_t property1, ssize_t property2, int decision1, int decision2)
{
if (property1 > property2)
return decision1;
else if (property2 > property1)
return decision2;
else
return 0;
}
some_func()
{
int decision = decide(!diamondsOnly.empty(), !clubsOnly.empty(), 1, 2);
if (!decision)
decision = decide(diamondsOnly.size(), clubsOnly.size(), 3, 4);
if (!decision)
decision = decide(diamondsOnly.back().value, clubsOnly.back().value, 3, 4);
bool flag;
switch (decision)
{
case 1:
flag = passHighCards(player.hand, getHighCards(Card::DIAMONDS), result);
break;
case 2:
flag = passHighCards(player.hand, getHighCards(Card::CLUBS), result);
break;
case 3:
flag = passHighCards(player.hand, getHighCards(Card::DIAMONDS), result);
flag = passHighCards(player.hand, getHighCards(Card::CLUBS), result);
break;
case 4:
flag = passHighCards(player.hand, getHighCards(Card::CLUBS), result);
flag = passHighCards(player.hand, getHighCards(Card::DIAMONDS), result);
break;
default:
flag = whatever();
break;
}
if (flag)
return result;
}
在上面的代码中,
开关
语句违反了DRY;如果您认为这仍然是一个问题,您可以使用“聪明”代码,将动作编码为各自的位:
- 第0位:是否要做任何事情
- 第一位:首先做什么
- 第二点:是否做第二件事
- 比特3:下一步该怎么办
然而,在我看来,这件“干兼容”的衣服看起来比开关更毛茸茸的 看一下真正的代码,我注意到的第一件事是,有很多几乎相同的调用,它们只按常量变化。我将使用复杂逻辑中设置的参数在一个地方进行调用
// 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;
}
//决定做什么。
std::向量通序;
如果(!diamondsOnly.empty()&&!clubsOnly.empty()){
//..复杂的逻辑为Passworder增加了适合性。。
}
//去做吧。
对于(auto-suit:passOrder){//这是C++11样式——根据需要进行更改
if(通过高牌(玩家手牌,获得高牌(套装),结果))
返回结果;
}
(如果向量总是一个或两个,那么使用向量可能会有点过头,但我假设真正的代码可能会处理所有的诉讼。)
这使它更容易阅读。程序员可以看到,首先你决定传递卡片的顺序,然后你实际传递卡片。两个独立的步骤将会更加清晰。只有一个称为Passcard的地方比在整个决策逻辑中分散使用Passcard的副本更不容易出现愚蠢的打字错误。它还将使调试变得更容易,因为您可以在非常特定的情况下设置断点,或者您可以在循环的开始处设置断点并检查passOrder
简化逻辑
接下来我们要简化决策逻辑
选项:
- 哨兵:部分复杂原因是,在某些情况下,您需要取消对其中一个容器中最后一张卡的引用,这可能是错误的
// return decision1 or decision2, depending on the result of comparison of properties // Note: type is ssize_t to accommodate bool, size_t and whatever type is 'value' int decision(ssize_t property1, ssize_t property2, int decision1, int decision2) { if (property1 > property2) return decision1; else if (property2 > property1) return decision2; else return 0; } some_func() { int decision = decide(!diamondsOnly.empty(), !clubsOnly.empty(), 1, 2); if (!decision) decision = decide(diamondsOnly.size(), clubsOnly.size(), 3, 4); if (!decision) decision = decide(diamondsOnly.back().value, clubsOnly.back().value, 3, 4); bool flag; switch (decision) { case 1: flag = passHighCards(player.hand, getHighCards(Card::DIAMONDS), result); break; case 2: flag = passHighCards(player.hand, getHighCards(Card::CLUBS), result); break; case 3: flag = passHighCards(player.hand, getHighCards(Card::DIAMONDS), result); flag = passHighCards(player.hand, getHighCards(Card::CLUBS), result); break; case 4: flag = passHighCards(player.hand, getHighCards(Card::CLUBS), result); flag = passHighCards(player.hand, getHighCards(Card::DIAMONDS), result); break; default: flag = whatever(); break; } if (flag) return result; }
if ((decision & 1) == 0) {flag = whatever;} else { thing1 = (decision & 2) ? Card::DIAMONDS : Card::CLUBS flag = passHighCards(player.hand, thing1, result); if (decision & 4) { thing2 = (decision & 8) ? Card::DIAMONDS : Card::CLUBS; flag = passHighCards(player.hand, thing2, 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; }
// 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; }