【问题标题】:How to make long parameter lists readable?如何使长参数列表可读?
【发布时间】:2010-01-28 17:47:19
【问题描述】:

我对函数中的长参数列表产生了一种自然的反感。虽然这在某种程度上是一件好事,但与代码重复或由于“手动内联”导致的冗长函数相比,有时长参数列表是两个弊端中较小的一个。至少让这些怪物中的一些人可读的好方法是什么?例如:

SomeClass[string] someFunction(SomeClass!(TemplateParam) foo, 
    string[][string] someAA, uint[] dataToProcess, SomeEnumType flag) {
    // Do stuff.
}

这在可读性方面得分不高,但在很多情况下四个参数是相当合理的。

【问题讨论】:

    标签: coding-style readability


    【解决方案1】:

    对于这种情况,我倾向于这样格式化:

    SomeClass[string] someFunction(
        SomeClass!(TemplateParam) foo, 
        string[][string] someAA,
        uint[] dataToProcess,
        SomeEnumType flag
    )
    {
        // Do stuff.
    }
    

    【讨论】:

    • 我同意。对于 very 长参数列表,每行一个参数也有它自己的问题....但只要您需要长参数列表,我从未见过任何其他更好的解决方案。当我这样做时,我也倾向于对齐类型和参数名称......可能会使其更具可读性。
    • 此外,如果您的参数列表比这长得多,这很好地表明一些重构是有序的。
    【解决方案2】:
    • 为了便于阅读 - 将每个参数换行
    • 为了可用性和更好的 API 设计 - 将相关参数分组到新类中,从而缩短参数数量。

    【讨论】:

      【解决方案3】:

      我在(主要是内部)类(或结构)中重新组合参数以避免广泛的函数声明/调用

      【讨论】:

      • 我也听说过有人这样做,但我不太喜欢创建一个新类或结构只是为了处理函数参数的想法。如果相同的参数列表(因此,相同的参数类/结构)被多次使用,我可能会更同意这个想法。我并不是说这一定是个坏主意,只是我个人不喜欢它。
      • 当我使用第三方库时,我偶然发现了一个带有许多参数的方法(我记得一个有 17 个!)带有十几个布尔标志,我希望这个 frankenstein 方法的创建者使用了类将他们重新组合到一个或多个类中!
      【解决方案4】:

      可以引入参数对象:

      class ParameterObject {
          public final SomeClass!(TemplateParam) foo; 
          public final string[][string] someAA;
          public final uint[] dataToProcess;
          public final SomeEnumType flag;
      
          private ParameterObject(
             SomeClass!(TemplateParam) foo, 
             string[][string] someAA,
             uint[] dataToProcess,
             SomeEnumType flag) {
             this.foo = foo;
             this.someAA = someAA;
             this.dataToProcess = dataToProcess;
             this.flag = flag;
          }
      
          private static class Builder {
              public SomeClass!(TemplateParam) foo; 
              public string[][string] someAA;
              public uint[] dataToProcess;
              public SomeEnumType flag;
      
              public Builder foo(SomeClass!(TemplateParam) foo) {
                  this.foo = foo;
                  return this;
              }
      
              public Builder someAA(string[][string] someAA) {
                  this.someAA = someAA;
                  return this;
              }
      
              public Builder dataToProcess(uint[] dataToProcess) {
                  this.dataToProcess = dataToProcess;
                  return this;
              }
      
              public Builder flag(SomeEnumType flag) {
                  this.flag = flag;
                  return this;
              }
      
              public ParameterObject build() {
                  if (null == foo) throw Exception("init foo!");
                  if (null == someAA) throw Exception("init someAA!");
                  if (null == dataToProcess) throw Exception("init dataToProcess!");
                  if (null == flag) throw Exception("init flag!");
                  return new ParameterObject(foo, someAA, dataToProcess, flag);
              }
          }
      }
      

      现在,您的调用将如下所示:

      SomeClass[string] myValue = 
         someFunction(
            new ParameterObject.Build().
                foo(myFoo).
                someAA(myAA).
                dataToProcess(myData).
                flag(false).
                build()
         );
      

      在允许创建内联映射的语言中处理类似情况要容易得多:

      someFunction(
          Map.new(
              foo => myFoo,
              someAA => myAA,
              dataToProcess => myData,
              flag => false
          )
      

      限定符final 表示只能从类的构造函数中设置字段。类前面的限定符 static 表示该类不绑定到它的外部类,即不能访问/改变它的字段。

      【讨论】:

      • dsimcha,你是绝对正确的。在像 Java 这样的语言中,这种解决方案的唯一好处是,如果您构建一个 API,并且您不想公开具有三个以上参数的构造函数或方法,这可能是一件好事。 API 消费者将受益匪浅
      • 请不要在原始表达式的末尾留下点,这很奇怪。以点开头的行清楚地表明它是上一行的继续调用。
      【解决方案5】:

      我喜欢 Aaron 的回复,只是为每个参数换行。

      当它变得太多时,是时候进行一些重构了。

      如果您仍然需要这么多参数,请改为传入一个包装您的属性的类。然后,您还可以轻松地将默认参数添加到您的方法中,而不会搞砸您的签名。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多