摆脱 switch-case 块
Geting rid of switch-case block
如何将这个 switch-case 块转换成好的代码?
private static void agentFieldContructor(Agent agent, String nodeName, String value) {
switch (nodeName) {
case "Description":
agent.setDescription(value);
break;
case "Model":
agent.setModel(value);
break;
(... +18)
}
}
agent
是一个对象,我根据指定的 nodeName
用 value
参数填充它。
每个 nodeName 都引用不同的代理属性,但我接收它时就像接收字符串一样,我无法更改它。我搜索了一些设计模式,但找不到任何可以帮助我的东西。
这里的问题不在于 switch-case 语句本身。而是 Agent class 本身的设计。首先,Agent 应该有一个适当的构造函数,您可以在其中传递属性值。如果这些值可以改变,那么 Agent 的用户应该直接调用 setters 而不是使用这个辅助函数。
更重要的是,具有 20 个属性的 class 很可能是重构的候选对象。尝试找到这些属性的子集之间的关系,这些子集可以分解为单独的 classes.
如果允许使用反射。
private static void agentFieldContructor(Agent agent, String nodeName, String value) {
Method setMethod = Agent.class.getMethod("set"+nodeName,String.class)
setMethod.invoke(Agent,value)
}
我完全同意评论。但是,如果您真的不想使用 switch case 并且您的方法名称和 case 字符串几乎相同,则可以使用反射。 Here 是可能对您有帮助的解决方案。
完成此任务的一种紧凑方法是通过反射。您可以访问 setter 方法并使用您的值调用它。
public static void agentFieldConstructor(Agent agent, String nodeName, String value) {
try {
agent.getClass().getDeclaredMethod("set" + nodeName, value.getClass()).invoke(agent, value);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
}
请注意,您将不得不处理:
- 如果他们插入无效的节点名称会怎样
- 如果值为意外值(如
null
)会发生什么情况
- 处理大小写混合的节点名称(现在,如果第一个字母大写,这就有效)
- 处理非标准节点名称(这将假定大部分 JavaBean 命名约定)
...所有这些都是 reader 的练习。
不使用 switch-case 或反射的另一种可能性是使用复杂的枚举。这里的枚举是 translators 从字符串键到 setter 调用:
public enum AgentFields {
DESCRIPTION {
@Override
public void setInAgent(Agent agent, String value) {
agent.setDescription(value);
}
},
MODEL {
@Override
public void setInAgent(Agent agent, String value) {
agent.setModel(value);
}
};
public abstract void setInAgent(Agent agent, String value);
// Call this method to set a named field's value
public static void agentFieldSetter(Agent agent, String nodeName, String value) {
AgentFields.valueOf(nodeName.toUpperCase()).setInAgent(agent, value);
}
}
这声明了一个枚举,每个字段有一个 "value",每个值都带有一个单独的 setter。调度是使用所有枚举自动提供的 valueOf() 方法完成的。我用 toUpperCase 修饰它以允许通常的大写枚举值约定,并使其不区分大小写。
如何将这个 switch-case 块转换成好的代码?
private static void agentFieldContructor(Agent agent, String nodeName, String value) {
switch (nodeName) {
case "Description":
agent.setDescription(value);
break;
case "Model":
agent.setModel(value);
break;
(... +18)
}
}
agent
是一个对象,我根据指定的 nodeName
用 value
参数填充它。
每个 nodeName 都引用不同的代理属性,但我接收它时就像接收字符串一样,我无法更改它。我搜索了一些设计模式,但找不到任何可以帮助我的东西。
这里的问题不在于 switch-case 语句本身。而是 Agent class 本身的设计。首先,Agent 应该有一个适当的构造函数,您可以在其中传递属性值。如果这些值可以改变,那么 Agent 的用户应该直接调用 setters 而不是使用这个辅助函数。
更重要的是,具有 20 个属性的 class 很可能是重构的候选对象。尝试找到这些属性的子集之间的关系,这些子集可以分解为单独的 classes.
如果允许使用反射。
private static void agentFieldContructor(Agent agent, String nodeName, String value) {
Method setMethod = Agent.class.getMethod("set"+nodeName,String.class)
setMethod.invoke(Agent,value)
}
我完全同意评论。但是,如果您真的不想使用 switch case 并且您的方法名称和 case 字符串几乎相同,则可以使用反射。 Here 是可能对您有帮助的解决方案。
完成此任务的一种紧凑方法是通过反射。您可以访问 setter 方法并使用您的值调用它。
public static void agentFieldConstructor(Agent agent, String nodeName, String value) {
try {
agent.getClass().getDeclaredMethod("set" + nodeName, value.getClass()).invoke(agent, value);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
}
请注意,您将不得不处理:
- 如果他们插入无效的节点名称会怎样
- 如果值为意外值(如
null
)会发生什么情况 - 处理大小写混合的节点名称(现在,如果第一个字母大写,这就有效)
- 处理非标准节点名称(这将假定大部分 JavaBean 命名约定)
...所有这些都是 reader 的练习。
不使用 switch-case 或反射的另一种可能性是使用复杂的枚举。这里的枚举是 translators 从字符串键到 setter 调用:
public enum AgentFields {
DESCRIPTION {
@Override
public void setInAgent(Agent agent, String value) {
agent.setDescription(value);
}
},
MODEL {
@Override
public void setInAgent(Agent agent, String value) {
agent.setModel(value);
}
};
public abstract void setInAgent(Agent agent, String value);
// Call this method to set a named field's value
public static void agentFieldSetter(Agent agent, String nodeName, String value) {
AgentFields.valueOf(nodeName.toUpperCase()).setInAgent(agent, value);
}
}
这声明了一个枚举,每个字段有一个 "value",每个值都带有一个单独的 setter。调度是使用所有枚举自动提供的 valueOf() 方法完成的。我用 toUpperCase 修饰它以允许通常的大写枚举值约定,并使其不区分大小写。