麻烦制造多态失败那些开关/案例陈述

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

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

我的设计是这样的:

 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;} 

显然,在某种程度上我设法击败了多态性对案例陈述的优势。

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

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

关于我一劳永逸地删除这些案例陈述的任何暗示或进一步的建议将受到高度赞赏。 提前谢谢了

我可能在这里遗漏了一些东西,但是没有switch语句,有什么问题

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

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

此外,如果您使用Java 5通用映射,则可以删除强制转换为Command 。 清理版本将是:

 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()); 

其次是:

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

使用简单的映射,因为你再次使用相同的CommandA实例,所以事情会变得很糟糕。

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

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

另一种方式是原型模式 (也就是克隆模式),它允许更灵活地处理多个不同类型(对于这个问题的命令):

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

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

我喜欢Skaffman的回答。 我只想补充一点:

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

  • 在一般情况下,输入要少得多。 它消除了错误。
  • 当名称不同时,您仍然可以为此特定情况配置地图。

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

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