我继承了一个项目,其中包含一些大型的switch语句块,有些包含多达20个case。如何重写这些代码?
我继承了一个项目,其中包含一些大型的switch语句块,有些包含多达20个case。如何重写这些代码?
为什么要以不同的结构重写它们?如果你真的有20个必须单独处理的情况,那么使用switch/case是最好的选择。一个庞大的if/then逻辑链将难以维护。
如果你正在使用面向对象的语言,多态性(polymorphism)是另一个选项。每个子类都会在方法中实现自己的功能。
正如其他人指出的那样,这取决于switch语句的情况。然而,在过去,我通过以下方式重构switch语句。假设我们有一个像这样的switch语句,其中有很多重复的代码:
switch(x){
case 1:
makeitso("foo");
globalLog += "foo";
case 2:
makeitso("bar");
globalLog += "bar";
case 3:
makeitso("baz");
globalLog += "baz";
...
default:
throw("input error");
}
首先要做的是识别那些共同的部分(在现实世界中,这可能会更加实质性一些)
makeitso([some string]);
globalLog += [some string];
function transformInput(somestring) {
makeitso(somestring);
globalLog += somestring;
}
对于每种情况下会改变的部分,可以使用哈希表或数组。
var transformvalues = ["foo", "bar", "baz"];
从这里我们可以做到这一点:
var tvals = ["foo", "bar", "baz" ... ];
function transformInput(somestring) {
makeitso(somestring);
globalLog += somestring;
}
var tval = tvals[x];
if(tval!==undefined) {
transformInput(tval);
} else {
throw ("invalid input");
}
如果将tvals从switch语句中分离出来,甚至可以在外部提供它以扩展您能够处理的情况数量。或者您可以动态构建它。然而,在现实世界中,switch语句通常会有特殊情况。这留给读者作为一个练习。
以下是三个建议(与已经给出的一些建议相呼应):
也许开关不像你想象的那么糟糕。如果case块很大,则可能会很丑陋。通过将逻辑提取到方法中来缩短它们。
在面向对象的语言中,多态可能是答案,正如许多人所指出的那样。
在像Javascript这样的函数式语言中,编写一个返回您需要运行任何输入的函数的函数。这可能会使用开关语句本身,或者可能会使用查找表。
在switch语句中有20个case并没有问题。您可以通过重构代码来整理它,并且至少将case处理移到方法/函数中。
这取决于switch语句的作用。
如果它匹配字符或字符串,比如在解析器中,并且您没有在代码中重复使用相同的模式集,则switch语句可能是可以接受的。
如果它匹配(比如)整数与允许值列表,则可以为每个值创建一个基类和一组派生类。然后,无论是什么生成了第一次的整数数据,都可以创建一个带有所有switch语句“答案”的派生类实例。
第三个选项是创建一个将模式映射到操作(即具有虚拟方法的函数或对象)的数据结构。您可以在此数据结构中查找switch值,并执行适当的操作。
如果程序没有重大错误(我指的是不会让你抓狂的错误),为什么要重构它呢?不要对所有东西都进行重构。
如果你想的话,可以将其更改为多态性,但这将是一种散弹手术,你可能需要重构比这个 switch 块更多的内容。