






















在开发工具型程序(如:数据转换、图像处理、批处理工具)时,一个常见的演进过程是:
一个
Main→ 一堆 if-else → 越来越难维护
本文介绍一种工程实践中非常成熟的做法:
用 Command 模式重构命令行工具,让每个功能成为一个独立命令(Command),主程序只负责调度(dispatch)。
传统写法通常是这样:
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
public interface ICommand
{
string Name { get; }
string Description { get; }
void Execute(CommandContext context);
}
Name:命令名(如 convert, export)Execute:命令执行入口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);
}
}
👉 每个命令一个类,职责单一
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);
}
}
主程序的特点:
Executepublic 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
命令行工具中,路径问题非常常见。
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);
}
}
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
非常适合:
甚至可以无缝接入 Unity Editor 或 CI 流水线。
通过 Command 模式重构命令行工具,可以获得:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。