用 Command 模式构建可扩展的命令行工具
用 Command 模式构建可扩展的 C# 命令行工具(支持多命令与路径解析)
在开发工具型程序(如:数据转换、图像处理、批处理工具)时,一个常见的演进过程是:
一个
Main→ 一堆 if-else → 越来越难维护
本文介绍一种工程实践中非常成熟的做法:
用 Command 模式重构命令行工具,让每个功能成为一个独立命令(Command),主程序只负责调度(dispatch)。
一、问题背景:为什么要重构 CLI 结构?
传统写法通常是这样:
static void Main(string[] args)
{
if (args[0] == "a") { /* 功能 A */ }
else if (args[0] == "b") { /* 功能 B */ }
else if (args[0] == "c") { /* 功能 C */ }
}
当功能增加后,会出现:
- •
Main过于臃肿 - • 功能之间强耦合
- • 不利于测试与扩展
- • 不利于长期维护
更合理的目标是:
新增一个命令,只新增一个文件
主程序不需要修改逻辑
二、设计目标
我们希望命令行工具具备以下特性:
- • 每个功能是一个独立命令
-
• 支持命令行传参(如
-i input -o output) - • 支持相对路径 / 绝对路径切换
- • 主程序只负责「分发命令」
三、整体架构概览
CLI Tool
│
├── Program.cs // 只做 dispatch
├── ICommand.cs // Command 抽象
├── CommandContext.cs // 参数 & 路径上下文
├── PathResolver.cs // 路径解析
│
├── Commands/
│ ├── CommandA.cs
│ ├── CommandB.cs
│ └── CommandC.cs
四、核心思想:Command 模式
1️⃣ Command 接口
public interface ICommand
{
string Name { get; }
string Description { get; }
void Execute(CommandContext context);
}
- •
Name:命令名(如convert,export) - •
Execute:命令执行入口
2️⃣ 示例 Command(功能模块)
public class CommandExample : ICommand
{
public string Name => "example";
public string Description => "Run example task";
public void Execute(CommandContext ctx)
{
string input = ctx.ResolvePath("i");
string output = ctx.ResolvePathOrDefault("o", "out.dat");
ExampleProcessor.Run(input, output);
}
}
👉 每个命令一个类,职责单一
五、主程序:只负责 Dispatch
class Program
{
static readonly List<ICommand> Commands = new()
{
new CommandExample(),
new CommandOther()
};
static void Main(string[] args)
{
var (cmdName, options) = ArgParser.Parse(args);
var command = Commands.FirstOrDefault(c => c.Name == cmdName);
if (command == null)
{
PrintHelp();
return;
}
var context = new CommandContext(options);
command.Execute(context);
}
}
主程序的特点:
- • 不包含业务逻辑
- • 不关心参数含义
- • 只负责:
- • 找到 Command
- • 调用
Execute
六、命令行参数解析(示例)
public static class ArgParser
{
public static (string, Dictionary<string, string>) Parse(string[] args)
{
string command = args[0];
var dict = new Dictionary<string, string>();
for (int i = 1; i < args.Length - 1; i++)
{
if (args[i].StartsWith("-"))
dict[args[i].TrimStart('-')] = args[++i];
}
return (command, dict);
}
}
示例调用:
tool.exe example -i data/input.json -o result.bin
七、路径处理:支持相对 / 绝对模式
命令行工具中,路径问题非常常见。
CommandContext
public class CommandContext
{
public Dictionary<string, string> Args { get; }
public string BaseDir { get; }
public CommandContext(Dictionary<string, string> args)
{
Args = args;
BaseDir = args.ContainsKey("absolute")
? Directory.GetCurrentDirectory()
: AppContext.BaseDirectory;
}
public string ResolvePath(string key)
{
return PathResolver.Resolve(Args[key], BaseDir);
}
}
PathResolver
public static class PathResolver
{
public static string Resolve(string path, string baseDir)
{
return Path.IsPathRooted(path)
? path
: Path.GetFullPath(Path.Combine(baseDir, path));
}
}
支持:
tool.exe example -i data/a.json
tool.exe example -i data/a.json --absolute
八、用到了哪些设计模式?
✅ Command Pattern(核心)
- • 每个命令封装一个操作
- • 主程序通过接口统一调用
✅ Strategy Pattern(弱形式)
- • 不同 Command = 不同执行策略
- • 运行时选择
✅ Context Object(工程实践)
- • 参数、路径、环境信息集中管理
- • Command 不直接依赖全局状态
九、这种结构适合什么场景?
非常适合:
- • 数据处理工具
- • 验证工具
- • Unity / OpenCV / Web 辅助工具
- • 内部工程 CLI 工具链
甚至可以无缝接入 Unity Editor 或 CI 流水线。
十、总结
通过 Command 模式重构命令行工具,可以获得:
- • 清晰的结构
- • 易扩展、易维护
- • 新功能零侵入
- • 工程级可读性
点赞鼓励下,(づ ̄3 ̄)づ╭❤~
作者:世纪末的魔术师
出处:https://www.cnblogs.com/Firepad-magic/
Unity最受欢迎插件推荐:点击查看
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号