简易终端命令解析器的命令模式设计问题求助
解决方案:引入命令工厂模式优化命令解析流程
针对你遇到的命令模式下参数延迟传递、冗余参数的问题,我们可以通过**命令工厂(Command Factory)**来重构现有逻辑,既保持命令模式的扩展性,又避免冗余参数和提前初始化命令对象的问题。
核心思路
- 将命令的创建逻辑从
CommandExecutionController中剥离,交给专门的工厂类处理 - 每个命令对应一个工厂,工厂负责校验参数并创建命令实例(此时参数已经解析完成)
- 保持
CommandInterface的纯净性,execute()方法不带冗余参数 - 注册和存储的是工厂而非命令类,解决参数延迟传递的问题
代码重构实现
1. 重构基础接口
首先定义纯净的命令接口和工厂接口:
// 命令接口:仅负责执行逻辑,无冗余参数 public interface CommandInterface { String execute(); } // 命令工厂接口:负责参数校验和命令实例创建 public interface CommandFactory { CommandInterface create(FileSystemModel fs, String[] args) throws IllegalArgumentException; }
2. 修改命令执行控制器
让控制器存储和管理工厂实例,而非命令类:
import java.util.HashMap; import java.util.Map; public class CommandExecutionController { private final Map<String, CommandFactory> commandFactories; private final FileSystemModel fileSystemModel; public CommandExecutionController(final FileSystemModel fileSystemModel) { this.commandFactories = new HashMap<>(); this.fileSystemModel = fileSystemModel; } public void register(final String commandName, CommandFactory factory) { commandFactories.put(commandName, factory); } public CommandInterface getDispatchedCommand(final String commandName, final String... arguments) { CommandFactory factory = commandFactories.get(commandName); if (factory == null) { throw new IllegalArgumentException("Command NOT found: " + commandName); } return factory.create(fileSystemModel, arguments); } }
3. 实现具体命令与工厂
以cd和help命令为例,命令类仅接收必要参数,工厂负责参数校验:
// CdCommand:仅接收FileSystem和路径参数,无冗余 public class CdCommand implements CommandInterface { private final String path; private final FileSystemModel fileSystemModel; public CdCommand(final FileSystemModel fileSystemModel, final String path) { this.path = path; this.fileSystemModel = fileSystemModel; } @Override public String execute() { return fileSystemModel.cd(path); } } // CdCommand工厂:校验参数数量,创建命令实例 public class CdCommandFactory implements CommandFactory { @Override public CommandInterface create(FileSystemModel fs, String[] args) { if (args.length != 1) { throw new IllegalArgumentException("cd command requires exactly 1 argument"); } return new CdCommand(fs, args[0]); } } // HelpCommand:仅接收FileSystem,无参数 public class HelpCommand implements CommandInterface { private final FileSystemModel fileSystemModel; public HelpCommand(final FileSystemModel fileSystemModel) { this.fileSystemModel = fileSystemModel; } @Override public String execute() { return "Available commands:\n- cd [path]: Change directory\n- mv [source] [dest]: Move file\n- help: Show help info"; } } // HelpCommand工厂:校验无参数,创建命令实例 public class HelpCommandFactory implements CommandFactory { @Override public CommandInterface create(FileSystemModel fs, String[] args) { if (args.length != 0) { throw new IllegalArgumentException("help command takes no arguments"); } return new HelpCommand(fs); } }
4. 注册与调用命令
注册时绑定命令名和对应工厂,调用时直接传递解析后的参数数组:
// 注册命令示例 FileSystemModel fs = new FileSystemModel(); CommandExecutionController controller = new CommandExecutionController(fs); controller.register("cd", new CdCommandFactory()); controller.register("help", new HelpCommandFactory()); controller.register("mv", new MvCommandFactory()); // 同理实现mv的工厂和命令 // 调用逻辑优化(修复原代码中参数join的错误) text = text.trim(); final String[] commandParts = text.split("\\s+"); if (commandParts.length == 0) { return "Empty command"; } try { final CommandInterface command = controller.getDispatchedCommand( commandParts[0], Arrays.copyOfRange(commandParts, 1, commandParts.length) ); return command.execute(); } catch (IllegalArgumentException e) { return e.getMessage(); }
方案优势
- 无冗余参数:每个命令的构造函数仅接收必要参数,避免
String...带来的冗余和不安全 - 扩展性强:新增命令只需实现
CommandInterface和CommandFactory,注册即可,无需修改核心控制器逻辑 - 职责分离:工厂负责参数校验和实例创建,命令类专注于执行逻辑,符合单一职责原则
- 避免提前初始化:命令实例在参数解析完成后才由工厂创建,完全适配解析流程
简化优化:用Lambda替代简单工厂
对于逻辑简单的命令,可以直接用Lambda表达式注册,无需单独编写工厂类:
controller.register("help", (fs, args) -> { if (args.length != 0) { throw new IllegalArgumentException("help takes no arguments"); } return new HelpCommand(fs); });
内容的提问来源于stack exchange,提问作者Celine
相关产品推荐
相关产品推荐

