我有一个特殊的问题,我有一个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
子类。
答案 0 :(得分:2)
正如您所想,您的CommandFactory
方法最接近正确。工厂/工厂方法通常用于此类问题。
你明显看到的唯一问题是这个CommandFactory
必须知道所有子事件,必须知道所有类型。这意味着,如果您添加新类型,则必须将其添加到CommandFactory
。
但是!你可以用例如来自ClassFinder
库的org.clapper.util
,以查找在类路径中实现Command
或扩展CommandFactory
的所有类。这样,您可以在以后添加任何新的Commands
,CommandFactory
仍会找到它们并将其添加到subFactories
。
你也可以扭转问题 - 让子工厂(或个人Commands
自己)了解工厂!首先使用ClassFinder
找到它们,然后在它们上面调用一个方法,将它们添加到工厂列表中。这与听众的工作方式类似。
答案 1 :(得分: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);
[ ... ]
}
听起来您想要使用构建器或abstract factory来构建所需的Command对象。如果你有一个大的if-else if链,你通常想要使用策略模式。
答案 2 :(得分:1)
我认为您需要Factory
和Chain 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中的工作方式。
答案 3 :(得分: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);
希望有所帮助。