2017-07-24 70 views
0

我的情况如下。选择合适的平滑CMD线arg加工设计模式

我有一个摘要Command类,它有一个exec方法。我有一系列扩展这个抽象类的具体命令类。

我有一个CommandFactory上下文类创建并返回一个适当的命令根据我解析并发送到工厂的cmdline参数。 (这里没有问题,我可以解析cmdline参数就好了)。

但是命令工厂内我有这样大的if-else - 如果不是不像这个

public Command getCmd(String cmdType){ 
    if(cmdType == null){ 
    return null; 
    }  
    if(cmdType.equalsIgnoreCase("CLEAN")){ 
    return new CleanCmd(); 

    } else if(cmdType.equalsIgnoreCase("KILL")){ 
    return new KillCmd(); 

    } else if(cmdType.equalsIgnoreCase("START")){ 
    return new StartCmd(); 
    } 

    return null; 
} 

注的名单:输入ARG游戏的一组标志和args这是范围太复杂这个问题。你可以把equalsIgnoreCase看作更复杂的东西。

但是我认为这个if else构造有点难看。我想用更优雅的东西来代替它。还纠正我,如果我错了当前的范式也违反开放原则,因为每次我添加一个新的命令我修改工厂?

回答

1

我建议尽可能使用两个概念:

Command模式想在这个answer描述,并使用一些依赖注入框架像春天或吉斯。

有了这个两个想法,你的代码可能是这样的:

class CommandFactory { 
    // Using spring. 
    // This will inject all the classes implementing Command. 
    @Autowired 
    List<Command> commandList;  

    // Mapping the command name to the implementation 
    Map<String, Command> commandMap;   

    // Initializing the command map 
    @PostConstruct 
    public void buildMap() { 
     for (Command command : commandList) { 
      commandMap.put(command.getType(), command); 
     } 
    } 

    public Command getCmd(String cmdType) { 
     return commandMap.get(cmdType); 
    } 
} 

利用这种配置,在类的CommandFactory就开闭原则。无需修改即可添加新命令,但可以按需接受新命令。

+0

嗯,但我的项目不使用春!但是,这很有趣,虽然 –

+0

你不能使用一些轻量级DI,如https://github.com/google/guice从谷歌?我看不出如何避免在没有DependencyInjection的情况下编写CommandFactory。但如果你想出其他解决方案,请告诉我学习!好的代码 – rafaelim

+0

好的,我会评估这个并且回复你。 –

0

我会建议一个原型设计模式来代替您正在使用的命令静态工厂(if-then ... ladder)。由于实例化的可能命令本质上是有限的,因此原型是生成命令的最佳模式。原型模式将保持Commands的预填充存储库,并且当客户端部分要求新命令时,它将从存储库获得所需的命令原型,并提供克隆作为具体命令。

0

做最简单的事情没有任何问题,直到它没有做到你所需要的。你可以做什么你已经做了,但稍微整齐

的一种方法,是使用基于字符串的switch声明:

switch(cmdType) { 
    case "KILL": 
     return new KillCommand(); 
    case "CLEAN": 
     return new CleanCommand(); 
    default: 
     throw new UnknownCommandException("Unknown command: " + cmdType); 
} 

我注意到你的null特殊处理。我敦促你尽量避免在任何地方返回null。如果你一直这样做,那么很多时候你不需要检查null。


如果您的需求变得更加复杂,考虑有一个Map<String,Command>

private static Map<String,Command> commandMap = new HashMap<>(); 
map.put("CLEAN", new CleanCommand()); 
map.put("KILL", new KillCommand()); 

...等等,然后:

public Command getCommand(String cmdString) { 
    return commandMap.get(cmdString.toUpperCase()); 
} 

注意这返回相同的情况下,每个时间 - 这往往是一件好事,如果你能确保命令类本身是不可变的和线程安全的。

如果你需要一个新的实例每次,你必须选择:

  • Map<Class<? extends Command>>和使用map.get(s).newInstance()
  • Map<Supplier<? extends Command>>和使用map.get(s).get()
  • Map<SpecificCommandFactory>,并使用从SpecificCommandFactory的方法(我会叫这只是CommandFactory如果你还没有定义这个)

使用这种模式意味着你已经准备好了一些其他技术,如果当你需要他们:

  • 使用使用框架(春,吉斯等)的依赖注入创建地图
  • 在初始时添加/删除命令(例如从配置文件)
  • 在运行时添加/删除命令