Sometimes one sees a Map being passed; primitive. But considering you are talking about possible 20 variations of parameters, something like properties, a Map, that is not really heavily processed, might be okay. This can even be passed as a fluent api of key-value pairs. Since java 9:
obj.method(Map.of("a", 1,
"b", 2,
"c", 3));
There is one solution that that is quite verbse, storing all parameters in its own class,
but would allow integrity constraints and checks, such as either pass A or otherwise pass B and C, setting A to f(B, C).
You can use a builder pattern. It comes with an object creation at the end with fields containing all possible parameters.
There are several variations in using builders. The most applicable for this case would be:
void method(Param param) { ... }
public class Param {
public final String s;
public final int x;
public final int y;
private Param(String s, int x, int y) {
this.s = s;
this.x = x;
this.y = y;
}
public static ParamBuilder newParam() { // Possibly obligatary parameters.
return new ParamBuilder();
}
Which ensures that one uses a special build to begin building the Param.
public static class ParamBuilder {
private String s;
private int x;
private int y;
private ParamBuilder() { };
public ParamBuilder withS(String s) {
...; return this;
}
public ParamBuilder withXY(int x, int y) {
...; return this;
}
public Param build() {
// Possible integrity checks for completeness.
return new Param(s, x, y);
}
}
}
Usage:
object.method(Param.newParam().withXY(3, 4).withZ(5).build());
object.pMethod().withXY(3, 4).withZ(5)).call();
// | |
// newParam method(build())