我正在尝试创建一个控制台来处理来自string
的控制台命令。
目前,我使用if语句检查每个命令,如下所示:
if (command.contains("new train")) {
command = command.replace("new train ", "");
Train t = new Train();
t.setCode(command);
ServiceProvider.getTrainService().saveOrUpdate(t);
responeHandler("train " + command + " created");
}
但在我看来,这不是最好的解决方案。
我想知道这样的问题是否已经有了一个好的设计模式?
我查看了builder
和factory
模式,但无法确定它们是否是正确的选择。
答案 0 :(得分:1)
Map<String, Consumer<String>>
可以完成将命令与动作相关联的工作
它不是GOF工厂和命令DP
但这些都是工厂和指令模式的公平和简单的实现
所以你也应该考虑它。
Map<String, Consumer<String>> actionsByCommand = new HashMap<>();
actionsByCommand.put("new train", command->{
command = command.replace("new train ", "");
Train t = new Train();
t.setCode(command);
ServiceProvider.getTrainService().saveOrUpdate(t);
responeHandler("train " + command + " created");
});
actionsByCommand.put("delete train", command->{
command = command.replace("delete train ", "");
...
});
// and so for...
您还可以为无需放入地图的无效命令创建特殊操作:
Consumer<String> invalidCommandAction = (command-> System.out.println("Invalid command. Here are the accepted commands..."));
为了提高动作类的可测试性和可维护性,您可以 把它们分成不同的类。
Map<String, Consumer<String>> actionsByCommand = new HashMap<>();
actionsByCommand.put("new train", new NewTrainCommand());
actionsByCommand.put("delete train", new DeleteTrainCommand());
将NewTrainAction
定义为:
public class NewTrainAction implements Consumer<String>{
public void accept(String command){
command = command.replace("new train ", "");
Train t = new Train();
t.setCode(command);
ServiceProvider.getTrainService().saveOrUpdate(t);
responeHandler("train " + command + " created");
}
}
其他动作以同样的方式定义。
然后你可以这样使用它们:
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String command = scanner.nextLine();
Consumer<String> action = actionsByCommand.getOrDefault(command, invalidCommandAction);
action.accept(command);
}
答案 1 :(得分:1)
可能是Command
和Factory
模式?
interface Command {
void execute();
}
interface CommandFactory {
boolean canCreate(String input);
Command fromInput(String input); // or return Optional so it can be a FunctionalInterface
}
class TrainCommand implements Command {
String train;
public TrainCommand(String t) { train = t; }
public void execute() {
ServiceProvider.getTrainService().saveOrUpdate(t);
}
}
class TrainCommandFactory {
public boolean canCreate(String t) {
return t.contains("new train ");
}
public Command fromString(String c) {
return new TrainCommand(c.replace("new train ", ""));
}
}
一个Singleton
Composite
CommandFactory迭代所有已知的命令工厂:
class CommandFactories implements CommandFactory {
private static final CommandFactories INSTANCE;
private List<CommandFactory> delegates = Arrays.asList(
new TrainCommandFactory()
// others
};
public boolean canCreate(String t) {
return delegates.stream()
.filter(cf -> cf.canCreate(t))
.findAny().isPresent();
}
public Command fromString(String c) {
return delegates.stream()
.filter(cf -> cf.canCreate(t))
.findAny()
.map(CommandFactory::fromString);
}
}
答案 2 :(得分:1)
您可以将命令存储在数组中,当用户输入命令时,您可以找到具有给定索引的项目。该索引在切换案例中有意义且可用,如果找不到该项,您可以给出有意义的回复。
此外,您可以以不区分大小写的方式执行此操作,使数组中的键都包含所有较低字符,并在搜索之前将命令键调低:
protected String[] supportedCommands = {"first", "second", "third"};
public static int findCommand(String command) {
for (var i = 0; i < supportedCommands.length; i++) {
if (command.equals(supportedCommands[i])) return i;
}
return -1; //Not found
}
public static void handleCommand(String command) {
int c = findCommand(command.toLowerCase());
switch (c) {
case 1: {/*...*/} break;
default: {/*Handle Undefined command*/}
}
}
答案 3 :(得分:1)
我认为使用已定义的命令是正确的方法。命令的一个重要问题是由matches
识别(commandString
)并执行(execute
)。创建自定义Command
后,您可以在列表中注册它们并执行它们。
interface Command{
boolean matches(String commandString);
boolean execute(String commandString);
}
示例实现将是
CreateTrainCommand implements Command{
private final CMDSTRING = "new train";
@Override
public boolean matches(CommandString cmdStr){
if(cmdStr != null && cmdStr.toLowerCase.startsWith(CMDSTRING)){
return true;
}
return false;
}
@Override
public boolean matches(CommandString cmdStr){
if(cmdStr != null){
String train = cmdString.toLowerCase.replace(CMDSTRING, "").trim();
//here comes your command execution
Train t = new Train();
...
}
return true;//execution succesful
}
}
如果要使用这些命令将所有命令存储到List(或任何其他集合)中,并检查命令是否与输入匹配
List<Command> cmds = ...
cmds.add(new CreateTrainCommand()); //add all commands that were implemented
//or only some commands if the user has restricted access
这是你如何应用命令
String commandString = ... //from Scanner or where else
for(Command cmd: cmds){ //use streams if you're java 8
if (cmd.matches(commandString)){
boolean wasSuccesful = cmd.execute(commandString);
break;
}
}
答案 4 :(得分:0)
如果你在Spring世界,你可以使用
您可以考虑实施
org.springframework.boot.CommandLineRunner
每个命令都可以在自己的CommandLineRunne实例中执行。
使用
org.springframework.core.env.SimpleCommandLinePropertySource
解析命令行