Coding style 如何使长参数列表可读?

Coding style 如何使长参数列表可读?,coding-style,readability,Coding Style,Readability,我天生厌恶函数中的长参数列表。虽然这在某种程度上是一件好事,但与代码重复或由于“手动内联”而导致的函数过长相比,有时长参数列表是两个弊病中较小的一个。什么是一个好方法,至少可以让这些怪物中的一些让人可读?例如: SomeClass[string] someFunction(SomeClass!(TemplateParam) foo, string[][string] someAA, uint[] dataToProcess, SomeEnumType flag) { // Do

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

SomeClass[string] someFunction(SomeClass!(TemplateParam) foo, 
    string[][string] someAA, uint[] dataToProcess, SomeEnumType flag) {
    // Do stuff.
}
SomeClass[string] myValue = 
   someFunction(
      new ParameterObject.Build().
          foo(myFoo).
          someAA(myAA).
          dataToProcess(myData).
          flag(false).
          build()
   );

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

对于这种情况,我倾向于如下格式:

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

我在一个(主要是内部)类(或结构)中重新组合参数,以避免大范围的函数声明/调用

我喜欢Aaron的回答,只是给每个参数加了一个换行符

当这太多的时候,是时候重构一下了

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

  • 为了便于阅读,请将每个参数放在新的一行
  • 为了可用性和更好的API设计,将相关参数分组到新类中,从而缩短参数的数量

您可以引入参数对象:

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] someFunction(SomeClass!(TemplateParam) foo, 
    string[][string] someAA, uint[] dataToProcess, SomeEnumType flag) {
    // Do stuff.
}
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
表示该类未绑定到其外部类,即无法访问/更改其字段。

我同意。对于很长的参数列表,每行一个参数也有自己的问题。。。。但我从未见过任何其他解决方案,只要您需要长参数列表,效果就会更好。我还倾向于在执行此操作时对齐类型和参数名称。。。可能会使它更具可读性。此外,如果您的参数列表比这长得多,这就很好地表明需要进行一些重构。我也听说有人这样做,但我不太喜欢创建一个新的类或结构来处理函数的参数。如果相同的参数列表(因此,相同的参数类/结构)被多次使用,我可能会更同意这个想法。我并不是说这一定是个坏主意,只是我个人不喜欢。当我使用第三方库时,我偶然发现一个有很多参数的方法(我记得有一个有17个参数!),带有十几个布尔标志,我希望这个弗兰肯斯坦方法的创建者使用一个类将它们重新组合到一个或多个类中!迪辛查,你说得绝对正确。在Java这样的语言中,此解决方案的唯一好处是,如果您构建了一个API,并且不想公开具有三个以上参数的构造函数或方法,那么这可能是一件好事。API消费者将从中受益。请不要在原始表达式的末尾留下点,这很奇怪。以点开头的行清楚地表明它是前一行的继续调用。