I've developed a natural aversion to long parameter lists in functions. While this is to some extent a good thing, sometimes long parameter lists are the lesser of two evils compared to c开发者_C百科ode duplication or ridiculously long functions due to "manual inlining". What's a good way to at least make some of these monstrosities human-readable? For example:
SomeClass[string] someFunction(SomeClass!(TemplateParam) foo,
string[][string] someAA, uint[] dataToProcess, SomeEnumType flag) {
// Do stuff.
}
This doesn't score high on the readability scale, but four parameters is pretty reasonable in a lot of cases.
For this kind of situation, I tend to format it like this:
SomeClass[string] someFunction(
SomeClass!(TemplateParam) foo,
string[][string] someAA,
uint[] dataToProcess,
SomeEnumType flag
)
{
// Do stuff.
}
- for the sake of readability - put each argument on new line
- for the sake of usability and better API desgin - group related arguments into new classes, thus shortening the number of arguments.
I regroup parameters in an (mostly inner) class (or a struct) to avoid wide function declaration/call
You can introduce parameter object:
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);
}
}
}
Now, your call would look for example:
SomeClass[string] myValue =
someFunction(
new ParameterObject.Build().
foo(myFoo).
someAA(myAA).
dataToProcess(myData).
flag(false).
build()
);
It's much easier to deal with similar cases in languages which allow creation of inline maps:
someFunction(
Map.new(
foo => myFoo,
someAA => myAA,
dataToProcess => myData,
flag => false
)
Qualifier final
means that a field can be set only from class's constructor. Qualifier static
in front of a class means that the class is not tied to it's outer class, i.e. can't access/mutate its fields.
I like Aaron's reply, just giving a newline for each param.
When that gets to be too much, then it's time to refactor a bit.
If you still need that many parameters, switch to passing in a class that wraps your properties instead. Then you get the added bonus of easily adding defaulted parameters to your method as well, without screwing up your signature.
精彩评论