建议对以下形式的 if 语句进行重构?
Suggested refactoring for if-statement of the following form?
我正在努力使它尽可能通用。假设在 if 语句中,我正在检查某个布尔表达式 A 是否为真。假设存在 A 为真的特定情况,A.a 和 A.b,它们是互斥的。另一个布尔表达式B也是如此。那么,考虑下面的代码:
if (A) {
if (A.a) {
somethingSpecificToAa();
foo();
}
} else if (B) {
if (B.a) {
somethingSpecificToBa();
foo();
}
} else {
foo();
}
在我的实际代码中 foo()
不是单个函数,而是多行长代码。重复这么多次对我来说似乎很臭,所以我假设一些重构是有序的。
因为foo()
执行时:
- A.a 是真的
- B.a 是真的
- A 和 B 都不正确
我想到了以下几点:
if (A.a) {
somethingSpecificToAa();
} else if (B.a) {
somethingSpecificToBa();
}
if (A.a || B.a || !(A || B)) {
foo();
}
应该具有相同的行为。这是最好的方法吗?请注意,第二个示例的第二个 if 语句中的条件实际上非常长,这就是为什么我的代码仍然看起来像第一个示例的原因(我讨厌将单个 if
分成几行。)我还考虑过制作一个 returns 相当于 A.a || B.a || !(A || B)
的 bool
的 lambda,并将 lambda 插入到第二个 if 语句中。或者,我可以保留第一个示例的结构,但将每个 foo()
的许多行替换为一个 (void
) lambda 来做同样的事情,尽管我不确定这是否能解决气味。
在这一点上我是不是过度设计了,考虑 lambda?哪种方法最能维护干净的代码?
编辑:我似乎已经太 了它的通用性。我正在处理 STL 容器,而不是我自己的 类,更 'accurate' 的例子是:
int shirtACleanliness = calculateCleanliness(shirtA);
if (itemsToWash.contains(shirtA)) { //itemsToWash is a std::set
if (shirtA.cleanliness > shirtACleanliness) {
itemsToWash.erase(shirtA);
shirtA.cleanliness = shirtACleanliness;
itemsToWash.insert(shirtA); //the set is ordered on cleanliness, so this re-inserts in the correct position
doSomeOtherStuff(shirtA);
}
} else if (itemsToDry.contains(shirtA)) { //itemsToDry is a std::vector
if (shirtA.cleanliness > shirtACleanliness) {
itemsToDry.erase(shirtA);
shirtA.cleanliness = shirtACleanliness;
itemsToWash.insert(shirtA);
doSomeOtherStuff(shirtA);
}
} else {
shirtA.cleanliness = shirtACleanliness;
itemsToWash.insert(shirtA);
doSomeOtherStuff(shirtA);
}
//am aware aware contains() is not a method for either type
//and std::vector does not have erase() by value, this is just conceptual
既然里面有一些通用代码,为什么不把它分解成一个函数呢?你可以有类似
的东西
template<typename T, typename F>
bool doSomething(T const& t, F f)
{
if (t && t.a)
{
f();
foo();
}
return static_cast<bool>(t);
}
并像
一样使用它
if (!doSomething(A, &somethingSpecificToAa) && !doSomething(B, &somethingSpecificToBa))
{
foo();
}
根据您最近的评论,这里有一些可能符合您的用例的伪代码。
Element* element=nullptr;
if(vectorA.contains(X)){
element = vectorA.get(X);
}else if(setB.contains(X)){
element = setB.get(X);
}
if(element != nullptr && element->a){
something(element);
}
if(element == nullptr || element->a){
foo();
}
我正在努力使它尽可能通用。假设在 if 语句中,我正在检查某个布尔表达式 A 是否为真。假设存在 A 为真的特定情况,A.a 和 A.b,它们是互斥的。另一个布尔表达式B也是如此。那么,考虑下面的代码:
if (A) {
if (A.a) {
somethingSpecificToAa();
foo();
}
} else if (B) {
if (B.a) {
somethingSpecificToBa();
foo();
}
} else {
foo();
}
在我的实际代码中 foo()
不是单个函数,而是多行长代码。重复这么多次对我来说似乎很臭,所以我假设一些重构是有序的。
因为foo()
执行时:
- A.a 是真的
- B.a 是真的
- A 和 B 都不正确
我想到了以下几点:
if (A.a) {
somethingSpecificToAa();
} else if (B.a) {
somethingSpecificToBa();
}
if (A.a || B.a || !(A || B)) {
foo();
}
应该具有相同的行为。这是最好的方法吗?请注意,第二个示例的第二个 if 语句中的条件实际上非常长,这就是为什么我的代码仍然看起来像第一个示例的原因(我讨厌将单个 if
分成几行。)我还考虑过制作一个 returns 相当于 A.a || B.a || !(A || B)
的 bool
的 lambda,并将 lambda 插入到第二个 if 语句中。或者,我可以保留第一个示例的结构,但将每个 foo()
的许多行替换为一个 (void
) lambda 来做同样的事情,尽管我不确定这是否能解决气味。
在这一点上我是不是过度设计了,考虑 lambda?哪种方法最能维护干净的代码?
编辑:我似乎已经太 了它的通用性。我正在处理 STL 容器,而不是我自己的 类,更 'accurate' 的例子是:
int shirtACleanliness = calculateCleanliness(shirtA);
if (itemsToWash.contains(shirtA)) { //itemsToWash is a std::set
if (shirtA.cleanliness > shirtACleanliness) {
itemsToWash.erase(shirtA);
shirtA.cleanliness = shirtACleanliness;
itemsToWash.insert(shirtA); //the set is ordered on cleanliness, so this re-inserts in the correct position
doSomeOtherStuff(shirtA);
}
} else if (itemsToDry.contains(shirtA)) { //itemsToDry is a std::vector
if (shirtA.cleanliness > shirtACleanliness) {
itemsToDry.erase(shirtA);
shirtA.cleanliness = shirtACleanliness;
itemsToWash.insert(shirtA);
doSomeOtherStuff(shirtA);
}
} else {
shirtA.cleanliness = shirtACleanliness;
itemsToWash.insert(shirtA);
doSomeOtherStuff(shirtA);
}
//am aware aware contains() is not a method for either type
//and std::vector does not have erase() by value, this is just conceptual
既然里面有一些通用代码,为什么不把它分解成一个函数呢?你可以有类似
的东西template<typename T, typename F>
bool doSomething(T const& t, F f)
{
if (t && t.a)
{
f();
foo();
}
return static_cast<bool>(t);
}
并像
一样使用它if (!doSomething(A, &somethingSpecificToAa) && !doSomething(B, &somethingSpecificToBa))
{
foo();
}
根据您最近的评论,这里有一些可能符合您的用例的伪代码。
Element* element=nullptr;
if(vectorA.contains(X)){
element = vectorA.get(X);
}else if(setB.contains(X)){
element = setB.get(X);
}
if(element != nullptr && element->a){
something(element);
}
if(element == nullptr || element->a){
foo();
}