咸阳市网站建设_网站建设公司_Logo设计_seo优化
2026/1/21 17:09:50 网站建设 项目流程

用 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
  • • 支持相对路径 / 绝对路径切换
  • • 主程序只负责「分发命令」

 

 

 

 

CommandXXX
CommandContext
Args
BaseDirectory
PathResolver

三、整体架构概览

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:命令名(如 convertexport
  • • 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 模式重构命令行工具,可以获得:

  • • 清晰的结构
  • • 易扩展、易维护
  • • 新功能零侵入
  • • 工程级可读性

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询