C# 什么是失控 switch 语句的最佳替代方案?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/410532/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the best alternative to an out of control switch statement?
提问by Asmussen
I have inherited a project that has some huge switch statement blocks, with some containing up to 20 cases. What is a good way to rewrite these?
我继承了一个项目,它有一些巨大的 switch 语句块,其中一些包含多达 20 个案例。什么是重写这些的好方法?
回答by Mitch Wheat
Polymorphism. But it may not be a trivial refactoring.
多态性。但这可能不是一个微不足道的重构。
Some examples and refs:
一些例子和参考:
回答by Andrew Hare
You could always use a lookup table.
您始终可以使用查找表。
回答by Dana Robinson
Why would you want to rewrite them in a different structure? If you really have 20 cases that have to be handled individually, a switch/case is the way to go. A big chain of if/then logic would be horrible to maintain.
为什么要以不同的结构重写它们?如果您真的有 20 个案例需要单独处理,那么 switch/case 是一种可行的方法。一个大的 if/then 逻辑链很难维护。
Polymorphism is another option if you are using an object-oriented language. Each subclass would implement it's own functionality in the method.
如果您使用面向对象的语言,则多态是另一种选择。每个子类将在方法中实现它自己的功能。
回答by scronide
There's nothing wrong with having 20 cases in a switch statement. You can tidy the code by refactoring and, at the very least, move the case processing into methods/functions.
在 switch 语句中包含 20 个 case 并没有错。您可以通过重构来整理代码,至少可以将案例处理转移到方法/函数中。
回答by Doug
It depends what the switch statement is doing.
这取决于 switch 语句在做什么。
If it's matching characters or strings, say in a parser, and you don't have the same set of patterns repeated everywhere in the code, then a switch statement might be ok.
如果它匹配字符或字符串,例如在解析器中,并且您没有在代码中到处重复相同的模式集,那么 switch 语句可能没问题。
If it's matching (say) an integer against a list of allowed values, you can create a base class and a set of derived classes for each value. Then, whatever generates the integer data in the first place can create an instance of the derived class with all of the switch statement "answers" instead.
如果它匹配(例如)一个整数与允许值列表,您可以为每个值创建一个基类和一组派生类。然后,首先生成整数数据的任何内容都可以创建派生类的实例,并使用所有 switch 语句“回答”。
A third option is to create a data structure that maps patterns to actions (i.e., functions or objects with virtual methods). You can look up the switch value in this data strucutre, and execute the appropriate action.
第三种选择是创建一个将模式映射到动作(即具有虚拟方法的函数或对象)的数据结构。您可以在此数据结构中查找开关值,并执行相应的操作。
回答by Agent_9191
Depending on what the switch statement is evaluating, you may want to refactor it using the Strategy Pattern. Take a look at this postfor an example of replacing a switch on enum values with separate classes to handle each function.
根据 switch 语句正在评估的内容,您可能希望使用策略模式对其进行重构。看看这篇文章的例子,用单独的类替换枚举值上的开关来处理每个函数。
It also may be that using the switch with 20 cases may actually be the best course of action for it. As long as it's readable and each result clearly conveys what the action is there's no need to really refactor it.
也可能将 switch 与 20 个案例一起使用实际上可能是它的最佳行动方案。只要它是可读的并且每个结果都清楚地传达了操作是什么,就没有必要真正重构它。
回答by hasen
if it's working without major bugs (by not major I mean they don't make you pull your hair out) why bother refactor it? Don't refactor everything.
如果它在没有重大错误的情况下工作(不是重大错误,我的意思是他们不会让你拔毛)为什么要重构它?不要重构一切。
If you want, you can change it to polymorphism, but this will be a shotgun surgery, you'll probably have to refactor a whole lot more than just this switch block.
如果您愿意,您可以将其更改为多态性,但这将是一个霰弹枪手术,您可能需要重构的不仅仅是这个 switch 块。
回答by Breton
As others have pointed out, it depends on the switch statement. However, in the past I have refactored switch statements by proceeding in the following way. Suppose we have a switch statement like this, with a lot of repeating code
正如其他人指出的那样,这取决于 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");
}
the first thing to do is to recognize the parts that are common (in the real world, this will probably be a littlemore substantial)
要做的第一件事就是要认识到是常见部分(在现实世界中,这将可能是一个小更大幅度)
makeitso([some string]);
globalLog += [some string];
and turn that into a function
并把它变成一个函数
function transformInput(somestring) {
makeitso(somestring);
globalLog += somestring;
}
then for the parts that change in each case, use a hash or an array;
然后对于每种情况下发生变化的部分,使用散列或数组;
var transformvalues = ["foo", "bar", "baz"];
from here we can do this:
从这里我们可以这样做:
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");
}
And with tvals factored out of the switch statement, it could even be provided externally to expand the number of cases you can handle. Or you could build it dynamically. In the real world, the switch statement will often have special cases, however. I leave that as an excercise for the reader.
并且将 tval 排除在 switch 语句之外,甚至可以从外部提供它以扩展您可以处理的案例数量。或者您可以动态构建它。然而,在现实世界中,switch 语句通常会有特殊情况。我把它留给读者作为练习。
回答by Gilad Naor
In general, I think you should refactor only when you need to, such as when you want to add more features, but the current design isn't up for the task. You should then refactor without adding the new functionality, and only then add the new feature.
一般来说,我认为您应该仅在需要时进行重构,例如当您想要添加更多功能时,但当前的设计不适合该任务。然后,您应该在不添加新功能的情况下进行重构,然后才添加新功能。
In other circumstances, don't bother with refactoring. Do it when you need to, otherwise there are probably more important things to do.
在其他情况下,不要理会重构。在需要的时候做,否则可能有更重要的事情要做。
If you really really need to, then the Visitor Design Patternis a common switch-case replacement, though you should note it does have drawbacks. (i.e., check out www.objectmentor.com/resources/articles/acv.pdf)
如果您真的需要,那么访问者设计模式是一种常见的 switch-case 替代品,但您应该注意它确实有缺点。(即,查看www.objectmentor.com/resources/articles/acv.pdf)
回答by slim
Three suggestions (echoing some already given):
三个建议(回应一些已经给出的建议):
Maybe a switch isn't as bad as you think. It can be ugly if the case blocks are large. Shorten them by extracting the logic into methods.
In an OO language, polymorphism might be the answer, as many have pointed out.
In a functional language, like Javascript, write a function that returns the function you need to run for whatever input. That might use a switch statement itself, or it might use a lookup table.
也许一个开关并不像你想象的那么糟糕。如果案例块很大,它可能会很丑陋。通过将逻辑提取到方法中来缩短它们。
正如许多人指出的那样,在面向对象语言中,多态性可能是答案。
在函数式语言(如 Javascript)中,编写一个函数,该函数返回您需要为任何输入运行的函数。这可能使用 switch 语句本身,也可能使用查找表。