4

我有一个特殊的问题,我有一个通用class Command的用于按顺序表示缓冲区中的命令。我也有它的几个子类,例如ComputeCommand, DefineCommand,DisplayCommand等。每个子类的构造函数都带有一个String参数,命令根据命令语法解析该参数,该命令语法因命令类型而异。

我希望能够做类似的事情:

String [] lines = { ... };
ArrayList<Command> commands = new ArrayList<Command>();
for(String line: lines){
    commands.add(new Command(line))
}

但是,我需要更专业的类来处理每个命令。

如果我可以定义构造函数,例如:

Command(String line){
    if(ComputeCommand.isValidComputeCommand(line))
        return new ComputeCommand(line);
    else if(DisplayCommand.isValidDisplayCommand(line))
        return new DisplayCommand(line);
    [ ... ]
}

这将完成我所需要的,但我们都知道构造函数不是这样工作的。

我想到的一种方法是包含一种方法

static Command getInstance(String line){ [...] }

执行该功能,但是我不确定在这种情况下这是正确的方法。

另一种可能的方法是为每个创建工厂类:

class CommandFactory(){
    CommandFactory [] subFactories = {new ComputeCommandFactory(), [...]};
    Command makeCommand(String line){
        for(CommandFactory subFactory: subFactories)
            if(subFactory.canMake(String line))
                return subFactory.makeCommand(line);
    }
    boolean canMake(String line){
        for(CommandFactory subFactory: subFactories)
            if(subFactory.canMake(String line))
                return true;
    }
}

我认为这可能是最正确的方法,但如果有更好的方法,我不想增加额外的复杂性。

在这种情况下使用什么正确的设计模式?

编辑:我还计划进一步对一些命令进行子类化,例如ComputeCommand可以有一个AddCommand或一个MultiplyCommand子类。

4

4 回答 4

2

如您所想,您的CommandFactory方法最接近正确。工厂/工厂方法通常用于此类问题。

您明显看到的唯一问题是它CommandFactory必须了解所有子工厂,必须了解所有类型。这意味着如果您添加一个新类型,您也必须将其添加到CommandFactory.

但!您可以使用例如库中的 查找在您的类路径中实现ClassFinder或扩展的所有类。这样,您以后可以添加任何新的,并且仍然会找到它们并将它们添加到.org.clapper.utilCommandCommandFactoryCommandsCommandFactorysubFactories

您还可以扭转问题-让子工厂(或个人Commands自己)了解工厂!首先用 找到它们ClassFinder,然后在它们上调用一个方法,将它们添加到工厂列表中。这与侦听器的工作方式类似。

于 2013-09-30T17:24:34.753 回答
1

我正在阅读的是您想根据上下文构建正确的对象吗?您有一些字符串,并且您想从该字符串的内容构建正确的对象?

您可以拥有一个 CommandBuilder/Factory,您可以在其中放置 if-else 逻辑以返回正确的命令。

public Command buildCommand(String line){
    if(ComputeCommand.isValidComputeCommand(line))
        return computeCommandFactory.buildCommand(line);
    else if(DisplayCommand.isValidDisplayCommand(line))
        return displayCommandFactory.buildCommand(line);
    [ ... ]

}

听起来您想使用构建器或抽象工厂来构建所需的 Command 对象。当您有一个较大的 if-else if 链时,您通常希望使用策略模式。

于 2013-09-30T16:43:22.520 回答
1

我认为你需要结合FactoryChain of Responsibility模式来做你想做的事。

interface CommandFactory{
    Command create(String line);

    void addToChain(CommandFactory next);
}

如果您的工厂无法处理给定的生产线,那么它将将该生产线传递给链中的下一个工厂:

class ComputeCommandFactory{


    CommandFactory next;

    Command create(String line){
        if(<can process>){
           return new ComputeCommand(line);
        }
        if(next ==null){
          throw Exception("can't process");
        }
        return next.create(line);
     }

 }

这样您就可以在以后添加新工厂(甚至在运行时)。这类似于在 Java 中添加类加载器和数据库驱动程序的工作方式。

于 2013-09-30T17:13:28.950 回答
1

你在正确的轨道上。您希望在这里使用的模式是工厂模式。你的想法是对的,模式只不过是那些被“写”在纸上的想法:)。

因此,对于您的情况,您可以执行以下操作:

public class CommandFactory
{
   public static Command getCommand (String line)
   {
      Command command = null;
      if (ComputeCommand.isValidComputeCommand (line))
      {
        command = new ComputeCommand (line);
      }
      else if (DisplayCommand.isValidDisplayCommand (line))
      {
        command = new DisplayCommand (line);
      }

     return command;
   }
}

并像这样使用它:

Command command = CommandFactory.getCommand (line);

希望有帮助。

于 2013-09-30T17:15:33.897 回答