是否有任何设计模式/方法/方法可以删除嵌套if then else条件/ switch语句?处理嵌套if/else嵌套switch语句
我记得有一些谷歌代码博客文章中列出的Google人使用的方法。现在似乎找不到它
是否有任何设计模式/方法/方法可以删除嵌套if then else条件/ switch语句?处理嵌套if/else嵌套switch语句
我记得有一些谷歌代码博客文章中列出的Google人使用的方法。现在似乎找不到它
您想要使用重构来替代使用多态类的条件。对于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的东西。对我来说基本上意味着你配置你的对象,然后你有一个基于配置的工厂和你给工厂的密钥动态创建合适的类。
如果你有方便的对象和多态性的作品。如果你不这样做,就痛苦。 – 2009-01-30 04:54:42
是的,如果逻辑非常简单,那么它可能不值得痛苦......但是如果在条件的每个主体中都有很多事情发生,那么简单地分解它可以减少复杂性在任何时候担心。 – JoshBerke 2009-01-30 04:58:10
doWork()如何传递正确的类型? – 2009-01-30 05:05:17
你不会说你正在使用什么语言,但是如果你使用的是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#中看起来也很相似。)在一个大型项目中,这是一个可维护性的胜利。
为什么downvotes人? – 2009-01-30 05:00:49
可能是因为虚函数是C++如何实现多态; +1反击怯懦驾车 - downvote – 2009-01-30 05:13:24
你读过Coding Horror的平面化箭头代码的this吗?
如果您使用的语言无异常,则可以使用return或goto替换throw。
我其实写了关于如何在2008年4月的博客中解决这个问题。看看here,让我知道你在想什么。
我建议你:
使用多态,让你需要在没有条件语句的正确运行时的行为。
把所有的条件语句,并将它们移动到某种“工厂”,它会在运行时提供给您适当的类型。
你完成了。不是那么容易吗? :)
如果您想查看一些实际的代码示例如何转换您的代码,请转到我的博客。
P.S.这不是一个便宜的自我推销尝试;我一直是SO用户很长一段时间,这是我第一次链接到我的博客 - 我只是这样做,因为我认为这是相关的。
您是否想过Google的“The Clean Code Talks -- Inheritance, Polymorphism, & Testing”视频?它讨论了使用面向对象技术去除if/switch条件的方法。
您可能想要看看Strategy Pattern,其中不是将长链if与链接条件放在一起,而是将每个条件抽象为不同的对象,每个对象都定义了它的特定行为。
定义这些对象的类将实现一个将由父对象调用的接口。
如何:
/* 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,如果合适的话。
你能举个例子吗? – Apocalisp 2009-01-30 07:01:32