mla*_*sen 264
Switch语句本身不是反模式,但如果你是面向对象的编码,你应该考虑是否更好地解决了交换机的使用问题 多态而不是使用switch语句来.
有了多态性,这个:
foreach (var animal in zoo) {
switch (typeof(animal)) {
case "dog":
echo animal.bark();
break;
case "cat":
echo animal.meow();
break;
}
}
Run Code Online (Sandbox Code Playgroud)
成为这个:
foreach (var animal in zoo) {
echo animal.speak();
}
Run Code Online (Sandbox Code Playgroud)
too*_*kit 228
请参阅切换语句气味:
通常,类似的switch语句分散在整个程序中.如果在一个开关中添加或删除子句,则通常还必须查找并修复其他子句.
如果您的(伪)代码如下所示:
class RequestHandler {
public void handleRequest(int action) {
switch(action) {
case LOGIN:
doLogin();
break;
case LOGOUT:
doLogout();
break;
case QUERY:
doQuery();
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
此代码违反了开放封闭原则,并且对于出现的每种新类型的操作代码都很脆弱.要解决这个问题,你可以引入一个'Command'对象:
interface Command {
public void execute();
}
class LoginCommand implements Command {
public void execute() {
// do what doLogin() used to do
}
}
class RequestHandler {
private Map<Integer, Command> commandMap; // injected in, or obtained from a factory
public void handleRequest(int action) {
Command command = commandMap.get(action);
command.execute();
}
}
Run Code Online (Sandbox Code Playgroud)
如果您的(伪)代码如下所示:
class House {
private int state;
public void enter() {
switch (state) {
case INSIDE:
throw new Exception("Cannot enter. Already inside");
case OUTSIDE:
state = INSIDE;
...
break;
}
}
public void exit() {
switch (state) {
case INSIDE:
state = OUTSIDE;
...
break;
case OUTSIDE:
throw new Exception("Cannot leave. Already outside");
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以引入一个'State'对象.
// Throw exceptions unless the behavior is overriden by subclasses
abstract class HouseState {
public HouseState enter() {
throw new Exception("Cannot enter");
}
public HouseState leave() {
throw new Exception("Cannot leave");
}
}
class Inside extends HouseState {
public HouseState leave() {
return new Outside();
}
}
class Outside extends HouseState {
public HouseState enter() {
return new Inside();
}
}
class House {
private HouseState state;
public void enter() {
this.state = this.state.enter();
}
public void leave() {
this.state = this.state.leave();
}
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助.
Pop*_*lin 40
switch是一种模式,无论是用switch语句实现的,if else链,查找表,oop多态,模式匹配还是其他.
您想要消除" switch statement "或" switch pattern "的使用吗?第一个可以被消除,第二个可以被消除,只有在可以使用另一个模式/算法时,并且大部分时间是不可能的,或者这不是更好的方法.
如果你想从代码中消除switch语句,首先要问的问题是消除switch语句和使用其他技术是有意义的.不幸的是,这个问题的答案是特定领域的.
请记住,编译器可以进行各种优化来切换语句.因此,例如,如果您想要有效地进行消息处理,那么切换语句几乎是可行的方法.但另一方面,基于switch语句运行业务规则可能不是最好的方法,应该重新构建应用程序.
以下是switch语句的一些替代方法:
Lar*_*ren 37
切换本身并没有那么糟糕,但是如果你的方法中的对象上有很多"switch"或"if/else",那么这可能表明你的设计有点"程序化"而你的对象只是价值桶.将逻辑移动到对象,调用对象上的方法,让他们决定如何响应.
Jos*_*osh 21
我认为最好的方法是使用一个好的地图.使用字典,您几乎可以将任何输入映射到其他值/对象/函数.
你的代码看起来像这样(psuedo):
void InitMap(){
Map[key1] = Object/Action;
Map[key2] = Object/Action;
}
Object/Action DoStuff(Object key){
return Map[key];
}
Run Code Online (Sandbox Code Playgroud)
Ber*_*ard 13
每个人都喜欢巨大的if else积木.这么容易阅读!我很好奇你为什么要删除switch语句.如果需要switch语句,则可能需要switch语句.说真的,我会说这取决于代码的作用.如果所有开关都在调用函数(比如说),你可以传递函数指针.它是否是一个更好的解决方案是值得商榷的.
我认为语言也是一个重要因素.
我认为你所寻找的是战略模式.
这可以通过多种方式实施,这些方法已在此问题的其他答案中提及,例如:
“switch”只是一种语言结构,所有语言结构都可以被认为是完成工作的工具。与真正的工具一样,有些工具比另一项更适合一项任务(您不会使用大锤来挂画钩)。重要的部分是如何定义“完成工作”。它是否需要可维护、是否需要快速、是否需要扩展、是否需要可扩展等等。
在编程过程的每个点上,通常都有一系列可以使用的结构和模式:开关、if-else-if 序列、虚函数、跳转表、带有函数指针的映射等等。有经验的程序员会本能地知道在给定情况下使用正确的工具。
必须假设任何维护或审查代码的人至少与原作者一样熟练,以便可以安全地使用任何构造。
switch 如果您发现自己在语句中添加了新状态或新行为,则最好替换这些语句:
int状态
字符串getString(){
开关(状态){
案例0://状态0的行为
返回“零”;
情况1://状态1的行为
返回“一个”;
}
抛出新的IllegalStateException();
}
double getDouble(){
切换(this.state){
案例0://状态0的行为
返回0d;
情况1://状态1的行为
返回1天;
}
抛出新的IllegalStateException();
}
添加新的行为需要复制switch,并增加新的状态意味着添加另一case对每一个 switch发言。
在Java中,您只能切换数量非常有限的原始类型,这些原始类型的值在运行时知道。这本身就是一个问题:状态被表示为幻数或字符。
模式匹配和多个if - else块都可以使用,尽管在添加新行为和新状态时确实存在相同的问题。
其他人建议的“多态性”解决方案是State模式的一个实例:
用自己的类替换每个状态。每个行为在类上都有自己的方法:
IState状态;
字符串getString(){
返回state.getString();
}
double getDouble(){
返回state.getDouble();
}
每次添加新状态时,都必须添加IState接口的新实现。在一个switch世界中,您将为case每个添加一个switch。
每次添加新行为时,都需要向IState接口和每个实现中添加新方法。尽管现在编译器将检查您是否在每个预先存在的状态上实现了新行为,但这和以前一样负担重。
其他人已经说过,这可能太重了,因此,当然有一点可以从一个位置移到另一个位置。就个人而言,我第二次编写开关是重构的关键。