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

时间:2009-09-06 20:41:06

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

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

然而,我仍然发现自己无法动摇这些案例陈述:我正在读取主/决定字符串中的每个字符,字符串由随机的,重复的字符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);

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

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

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

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

3 个答案:

答案 0 :(得分:14)

我可能在这里遗漏了一些东西,但是没有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();

答案 1 :(得分:0)

使用简单的地图,因为您再次使用相同的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,这可能非常耗时。

答案 2 :(得分:0)

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

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

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

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

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