是否有任何设计模式/方法/方法可以删除嵌套if else else condition / switch语句?
我记得在Google代码博客文章中列出了Google人员使用的一些方法。现在似乎无法找到它
答案 0 :(得分:8)
您是否阅读过{Coding Horror中展平箭头代码的this?
如果你使用的是没有例外的语言,你可以用throw或goto替换throw。
答案 1 :(得分:6)
您希望使用使用多态类替换条件的重构。对于example。
或者这是另一个example
基本上理想是非常简单的创建对象层次,并将各种行为移动到覆盖方法中。您仍然需要一种方法来创建正确的类,但这可以使用工厂模式完成。
让我补充一点,在每种情况下,这都不是一个完美的解决方案。因为(我忘了你的名字对不起)在我的评论中指出,有时候这可能是一种痛苦,特别是如果你必须创建一个对象模型来做这件事。如果你有这个重构,那么这个重构是非常好的:
function doWork(object x)
{
if (x is a type of Apple)
{
x.Eat();
} else if (x is a type of Orange)
{
x.Peel();
x.Eat();
}
}
在这里,您可以将切换重构为每个水果将处理的新方法。
正如有人指出你如何创建正确的类型进入doWork,有更多的方法可以解决这个问题,然后我可以列举一些基本的方法。第一个也是最直接的(是的,与这个问题相反)是一个开关:
class FruitFactory
{
Fruit GetMeMoreFruit(typeOfFruit)
{
switch (typeOfFruit)
...
...
}
}
这种方法的优点是它易于编写,通常是我使用的第一种方法。虽然你仍然有一个switch语句,它被隔离到一个代码区域并且非常基本,它返回的是一个n对象。如果你只有几个对象和它们;不改变它的效果非常好。
您可以查看的其他更多强制模式是Abstract Factory。如果您的平台支持,您也可以动态创建Fruit。您也可以使用类似Provider Pattern的内容。这对我来说意味着你配置你的对象然后你有一个工厂,它基于配置和你给工厂的密钥动态创建正确的类。
答案 2 :(得分:3)
我实际上在2008年4月写了关于如何在我的博客中解决这个问题。看看here并告诉我你的想法。
我建议你:
使用多态来获得所需的正确运行时行为,而无需条件语句。
获取所有条件语句,并将它们移动到某种“工厂”中,该工厂将在运行时向您提供适当的类型。
你已经完成了。那不容易吗? :)
如果您想查看有关如何转换代码的实际代码示例,请访问我的博客。
P.S。这不是一种廉价的自我推销尝试;我已经很长时间以来一直是SO用户,这是我第一次链接到我的博客 - 而且我之所以这样做是因为我认为它是相关的。
答案 3 :(得分:2)
您是否在考虑Google的“The Clean Code Talks -- Inheritance, Polymorphism, & Testing”视频?它讨论了使用面向对象技术来删除if / switch条件的方法。
答案 4 :(得分:1)
您没有说出您正在使用的语言,但如果您使用的是OO语言,例如C ++,C#或Java,您通常可以使用虚函数来解决同样的问题。您目前正在使用switch
语句以更可扩展的方式进行求解。在C ++的情况下,比较:
class X {
public:
int get_type(); /* Or an enum return type or similar */
...
};
void eat(X& x) {
switch (x.get_type()) {
TYPE_A: eat_A(x); break;
TYPE_B: eat_B(x); break;
TYPE_C: eat_C(x); break;
}
}
void drink(X& x) {
switch (x.get_type()) {
TYPE_A: drink_A(x); break;
TYPE_B: drink_B(x); break;
TYPE_C: drink_C(x); break;
}
}
void be_merry(X& x) {
switch (x.get_type()) {
TYPE_A: be_merry_A(x); break;
TYPE_B: be_merry_B(x); break;
TYPE_C: be_merry_C(x); break;
}
}
与
class Base {
virtual void eat() = 0;
virtual void drink() = 0;
virtual void be_merry() = 0;
...
};
class A : public Base {
public:
virtual void eat() { /* Eat A-specific stuff */ }
virtual void drink() { /* Drink A-specific stuff */ }
virtual void be_merry() { /* Be merry in an A-specific way */ }
};
class B : public Base {
public:
virtual void eat() { /* Eat B-specific stuff */ }
virtual void drink() { /* Drink B-specific stuff */ }
virtual void be_merry() { /* Be merry in an B-specific way */ }
};
class C : public Base {
public:
virtual void eat() { /* Eat C-specific stuff */ }
virtual void drink() { /* Drink C-specific stuff */ }
virtual void be_merry() { /* Be merry in a C-specific way */ }
};
优点是您可以添加新的Base
- 派生类D
,E
,F
等,而无需触及任何仅处理指针的代码或Base
的引用,因此没有任何内容可以像switch
语句在原始解决方案中那样过时。 (在Java中,转换看起来非常相似,默认情况下方法是虚拟的,我确信它在C#中看起来也很相似。)在大型项目中,这是巨大的可维护性获胜。
答案 5 :(得分:1)
您可能希望查看Strategy Pattern,其中不是将一长串ifs与链接条件放在一起,而是将每个条件抽象为另一个对象,每个对象定义其特定行为。
定义这些对象的类将实现一个将由父对象调用的接口。
答案 6 :(得分:0)
怎么样:
/* Code Block 1... */
if(/* result of some condition or function call */)
{
/* Code Block 2... */
if(/* result of some condition or function call */)
{
/* Code Block 3... */
if(/* result of some condition or function call */)
{
/* Code Block 4... */
}
}
}
成为这个:
/* Code Block 1... */
IsOk = /* result of some condition or function call */
if(IsOK)
{
/* Code Block 2... */
IsOk = /* result of some condition or function call */
}
if(IsOK)
{
/* Code Block 3...*/
IsOk = /* result of some condition or function call */
}
if(IsOK)
{
/* Code Block 4...*/
IsOk = /* result of some condition or function call */
}
/* And so on... */
如果IsOk在适当的时候变为假,你当然可以返回。