摆脱 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 是一个对象,我根据指定的 nodeNamevalue 参数填充它。
每个 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 修饰它以允许通常的大写枚举值约定,并使其不区分大小写。