2013-09-30 44 views
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可以有一个AddCommandMultiplyCommand子类。

+2

只需要注意一点:'static命令getInstance(String line){[...]}'_already_是工厂方法。您不必为了拥有工厂方法而引入新类。 –

回答

2

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

你明显看到的唯一问题是,这个CommandFactory必须知道所有的子因素,必须知道所有的类型。这意味着如果你添加一个新类型,你也必须将它添加到CommandFactory

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

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

1

我正在阅读的是,你想基于上下文建立正确的对象吗?你有一些字符串,你想从该字符串的内容构建正确的对象?

你可以有一个CommandBuilder /工厂,这就是你可以放置你的if-else逻辑返回正确的命令。

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

} 

这听起来像你想用建设者或abstract factory来构建你需要的Command对象。当你有一个大的if-else if链时,你通常要使用一个策略模式。

+1

海报还应该考虑使用诸如ANTLR或JavaCC的词法分析器,而不是试图处理每个命令类中的所有决策。我从来没有用过,但是当我使用C,C++和Obj-C编程时,我已经使用过lex/yacc。 –

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中的工作方式类似。

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

希望有所帮助。