【问题标题】:Lot of command line arguments for different classes不同类的很多命令行参数
【发布时间】:2014-03-12 11:06:29
【问题描述】:

我们使用特定的软件来执行我的控制台应用程序,并带有很多参数(现在是 25(!)并且可能越来越多)。当然,不同的类需要不同的论据。我用 NDesk.Options 解析它。但是,我一次又一次地为所有课程这样做。

class A {
    A (IEnumerable<String> args){
        new OptionSet {
            { "arg1=", value => foo1 = value },
                { "arg2=", value => foo2 = value },
            ...
        }.Parse(args);
    }
}
class B {
    B (IEnumerable<String> args){
        new OptionSet {
            { "arg10=", value => foo10 = value },
                { "arg11=", value => foo11 = value },
            ...
        }.Parse(args);
    }
}

如何制作出好的设计?解析静态类中的所有参数并使用它或其他什么?

【问题讨论】:

  • 一个“好的设计”是相对的。您的设计质量之一可能是可维护性。您可以努力使添加新参数变得更容易(听起来这就是给您带来麻烦的原因)。然后,您将努力隔离元素以最大程度地减少这些更改的影响。你的问题领域的什么特点使论点如此不稳定?
  • @Fuhrmanator,逻辑很简单,控制台应用程序需要用这个参数启动一些.exe文件。并且每周它可能需要额外的参数(就像现在,我添加了 10 个参数)。我反对它,但我的技术主管坚持这样的架构......
  • 如果论点(要求)每周都在变化,而您无法确定某种原因,那么很难做出一个简单的设计。如果您能识别出激发这些新论点的外部力量,您也许可以设计成更容易整合它们。如果您不指定详细信息,我很难提出更多建议。

标签: c# parsing design-patterns command-line


【解决方案1】:

由于您要求设计模式,这听起来像是 Interpreter pattern 的工作。

否则,根据我的经验,命令行参数“解析”是模式匹配的一个很好的例子,不幸的是,C# 没有,但 F# 有。在ZeroToNine 中,参数匹配当前如下所示:

let Parse argv =
    match argv |> Seq.toList with
    | ["-l"] -> ListVersions
    | ["-a"; IsProperVersionString version] -> Assign version
    | ["-i"; "major"] -> Increment Rank.Major
    | ["-i"; "minor"] -> Increment Rank.Minor
    | ["-i"; "build"] -> Increment Rank.Build
    | ["-i"; "patch"] -> Increment Rank.Build
    | ["-i"; "revision"] -> Increment Rank.Revision
    | ["-a"; "major"; IntegerGreaterThanOrEqualToZero rankValue] -> AssignRank(Rank.Major, rankValue)
    | ["-a"; "minor"; IntegerGreaterThanOrEqualToZero rankValue] -> AssignRank(Rank.Minor, rankValue)
    | ["-a"; "build"; IntegerGreaterThanOrEqualToZero rankValue] -> AssignRank(Rank.Build, rankValue)
    | ["-a"; "patch"; IntegerGreaterThanOrEqualToZero rankValue] -> AssignRank(Rank.Build, rankValue)
    | ["-a"; "revision"; IntegerGreaterThanOrEqualToZero rankValue] -> AssignRank(Rank.Revision, rankValue)
    | ["-?"] -> ShowHelp
    | ["-h"] -> ShowHelp
    | [] -> ShowHelp
    | x -> Unknown(x)
    |> Seq.singleton

诚然,我们没有 25 个不同的参数,但上面的示例仍然应该让您很好地了解处理各种情况是多么容易。

即使您有 C# 代码库,也可以用 F# 编写解析器库。

稍有不同:如果您的控制台应用程序采用 25 个不同的参数,那么将其拆分为几个较小的控制台应用程序是否有意义?听起来它做了很多。

【讨论】:

  • Iterpreter 不会过度设计吗?参数通常不是句法语言,OP给出的例子看起来很简单。我不确定design-patterns 总是意味着四人组设计模式(谢天谢地)。
  • 两个参数怎么样? F.e. app.exe -i major -i minor
  • 列表模式可以匹配两个以上的元素:msdn.microsoft.com/en-us/library/dd547125.aspx 你也可以嵌套模式匹配,或者使用Active Patterns
【解决方案2】:

Builder pattern 可用于使用命令行参数配置解析器和/或类。这避免了具有大量参数的构造函数,其中一些参数可能是可选的。它允许轻松添加新参数。

Apache 有一个很好的 Builder 与命令行解析一起使用的例子。

另一方面,Builder 是有风险的。它有时用于避免具有太多参数的构造函数的反模式。这是一种反模式的原因是因为您可能会暴露太多的类机密(实现细节),或者同样糟糕的是,类有太多的责任。

正如我在对您的问题的评论中提到的那样,论点众多且一直在变化的事实可能表明高级设计不佳。没有更多细节很难说。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 2012-07-21
    • 2017-11-04
    • 2015-11-30
    • 1970-01-01
    相关资源
    最近更新 更多