【问题标题】:trouble making polymorphism defeat those switch/case statements麻烦使多态性打败那些 switch/case 语句
【发布时间】:2010-11-26 01:54:00
【问题描述】:

继续前面的问题(herehere),我实现了一个基本的命令模式,创建了我的命令类并编码到一个接口,所以当使用任何命令时,调用execute() 方法。

但是,我仍然发现自己无法动摇这些案例陈述:我正在从一个主/决策字符串中读取每个字符,该字符串由随机的重复字符 A、B、C 或 D 组成,然后我检索从地图中执行命令的相关实现并调用其执行方法。

我的设计是这样的:

public interface Command {
    void execute();
}

public class CommandA implements Command{
  //implements execute() method
}

private Map myMap= new HashMap();
myMap.put("A", new CommandA);
myMap.put("B", new CommandB);
myMap.put("C", new CommandC);
myMap.put("D", new CommandD);

但是,当我阅读每条指令时,我不得不再次求助于案例陈述:

switch(instructionFromString){
case 'A':{myMap.get("A").execute(); break;}
case 'B':{myMap.get("B").execute(); break;}
case 'C':{myMap.get("C").execute(); break;}
case 'D':{myMap.get("D").execute(); break;}

显然,在此过程中,我设法克服了多态性对 case 语句的优势。

可能是我选择用来存储命令的那种数据结构吗?它很可能是一个永久的数据结构,可以从中提取这些命令。

我想到的另一件事是我在地图中使用的键/值命名。我试图在概念上将每个存储的命令链接到其相关指令的方式?即命令“A”的实现,用键“A”存储在地图上,这样它就可以匹配相应的指令“A”?不过在我看来这有点不太可能。

任何关于我下一步一劳永逸地删除这些案例陈述的提示或进一步建议将不胜感激。非常感谢提前

【问题讨论】:

    标签: java design-patterns polymorphism conditional switch-statement


    【解决方案1】:

    我可能在这里遗漏了一些东西,但不是switch 声明,而是有什么问题

    ((Command)myMap.get(instructionFromString)).execute();
    

    如果 instructionFromString 是 char,则在进行映射查找之前将其转换为 String,否则在映射中使用 Character 键。

    此外,如果您使用 Java 5 通用映射,那么您可以移除对 Command 的强制转换。清理后的版本是:

    private Map<Character, Command> myMap = new HashMap<Character, Command>();
    myMap.put('A', new CommandA());
    myMap.put('B', new CommandB());
    myMap.put('C', new CommandC());
    myMap.put('D', new CommandD());
    

    接着是:

    char instructionFromString = ....
    myMap.get(instructionFromString).execute();
    

    【讨论】:

    • @skaffman:对不起。我设法以某种方式阅读了代码示例,但错过了上面和下面的文本。
    • @skaffman:谢谢,非常优雅的 asnwer。不敢相信我错过了!
    • 另外,使用泛型。不要使用原始集合
    【解决方案2】:

    使用简单的地图,事情可能会变得很糟糕,因为您再次使用CommandA 的同一个实例。

    封装这种行为的好方法是工厂

    public class CommandFactory
    {
        public Command CreateCommand(String instruction)
        {
            if (instruction.equals("A"))
                return new CommandA();
            else if ...
        }
    }
    

    另一种方法是 prototype pattern(又名克隆模式),它允许更灵活地处理多种不同类型(与此相关的命令):

    public class CommandFactory
    {
        private Map<String, Command> commands = new HashMap<String, Command>();
    
        public void RegisterCommand(String instruction, Command commandTemplate)
        {
            commands.put(instruction, commandTemplate);
        }
    
        public Command CreateCommand(String instruction)
        {
            return commands.get(instruction).clone();
        }
    }
    

    您可能已经注意到,您必须在Commands 中实现克隆行为,这可能很耗时。

    【讨论】:

      【解决方案3】:

      我喜欢斯卡夫曼的回答。我只想补充一点:

      为了命名您的命令,您可以使用更简单的模式。例如,您可以使用命令的名称作为默认情况。

      • 在一般情况下,要键入的内容要少得多。它消除了错误。
      • 当名称不同时,您仍然可以针对这种特定情况配置地图。

      许多技术可用于关联名称和命令。例子:

      • 类的注释,用于指定命令名称(默认值等于类的名称)。
      • Spring 配置已经是这么大的 Map,直接下发对应的对象,一路上还有更多的服务可用。
      • Java 枚举也自然地将名称与对象相关联。此外,它们还允许您在 IDE 中进行完成和编译时检查,以及“参考搜索”和其他好东西。

      【讨论】:

      • @KLE:谢谢!那里也有非常有用的提示。
      猜你喜欢
      • 1970-01-01
      • 2015-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-19
      • 1970-01-01
      • 1970-01-01
      • 2013-09-24
      相关资源
      最近更新 更多