2009-01-30 137 views
10

是否有任何设计模式/方法/方法可以删除嵌套if then else条件/ switch语句?处理嵌套if/else嵌套switch语句

我记得有一些谷歌代码博客文章中列出的Google人使用的方法。现在似乎找不到它

+0

你能举个例子吗? – Apocalisp 2009-01-30 07:01:32

回答

5

您想要使用重构来替代使用多态类的条件。对于example

或者这里的另一个example

本质的理想很简单,你创建一个对象层级结构中,移动的各种行为为覆盖方法。你仍然需要一种方法来创建合适的类,但这可以使用工厂模式来完成。

编辑

让我补充一点,这是不是在所有情况下的完美解决方案。由于(我忘了你的名字对不起)在我的评论中指出,有时这可能是一个痛苦,特别是如果你必须创建一个对象模型来做到这一点。这种重构excells如果你有这样的:

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,有更多的方式来解决这个问题,那么我可以probally列出这样一些基本的方法。第一个也是最简单的(是违背了这个问题的谷物)是一个开关:

class FruitFactory 
{ 
    Fruit GetMeMoreFruit(typeOfFruit) 
    { 
     switch (typeOfFruit) 
     ... 
     ... 
    } 
} 

对这种做法的好处是很容易写的,是我通常使用第一种方法。虽然你仍然有一个switch语句将其隔离到一个代码区域,并且它非常基本,但它返回的是一个n对象。如果你只有几个物体,并且不改变它,那么这个工作就不会很好。

你可以看到的其他更多compelx模式是Abstract Factory。如果您的平台支持,您也可以动态创建Fruit。你也可以使用类似Provider Pattern的东西。对我来说基本上意味着你配置你的对象,然后你有一个基于配置的工厂和你给工厂的密钥动态创建合适的类。

+0

如果你有方便的对象和多态性的作品。如果你不这样做,就痛苦。 – 2009-01-30 04:54:42

+0

是的,如果逻辑非常简单,那么它可能不值得痛苦......但是如果在条件的每个主体中都有很多事情发生,那么简单地分解它可以减少复杂性在任何时候担心。 – JoshBerke 2009-01-30 04:58:10

+0

doWork()如何传递正确的类型? – 2009-01-30 05:05:17

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派生类DEF等,而无需接触任何代码只处理指针或Base的引用,所以没有什么可以像原始解决方案中的switch语句那样过时。(在Java中,转换看起来非常相似,默认情况下方法是虚拟的,我相信它在C#中看起来也很相似。)在一个大型项目中,这是一个可维护性的胜利。

+0

为什么downvotes人? – 2009-01-30 05:00:49

+0

可能是因为虚函数是C++如何实现多态; +1反击怯懦驾车 - downvote – 2009-01-30 05:13:24

7

你读过Coding Horror的平面化箭头代码的this吗?

如果您使用的语言无异常,则可以使用return或goto替换throw。

3

我其实写了关于如何在2008年4月的博客中解决这个问题。看看here,让我知道你在想什么。

我建议你:

  1. 使用多态,让你需要在没有条件语句的正确运行时的行为。

  2. 把所有的条件语句,并将它们移动到某种“工厂”,它会在运行时提供给您适当的类型。

  3. 你完成了。不是那么容易吗? :)

如果您想查看一些实际的代码示例如何转换您的代码,请转到我的博客。

P.S.这不是一个便宜的自我推销尝试;我一直是SO用户很长一段时间,这是我第一次链接到我的博客 - 我只是这样做,因为我认为这是相关的。

1

您可能想要看看Strategy Pattern,其中不是将长链if与链接条件放在一起,而是将每个条件抽象为不同的对象,每个对象都定义了它的特定行为。

定义这些对象的类将实现一个将由父对象调用的接口。

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当然返回false,如果合适的话。