Reputation: 706
I have a class as follows :
public class Foo {
private double A;
private double B;
...
private double K;
}
It should contain 11 tightly bound parameters, A-K, which describes movement of a point in earths orbit (a sort of coordinate). By that, I mean they cannot be divided into subclasses or other meaningful parts since they all share the same purpose and meaning. All of those parameters should be instantiated together inside a constructor, so another class could make necessary calculations with Foo
and those 11 fields.
I've been given a comment about the quantity of parameters inside constructor being too many.
Is there another way to initialize a Foo
object without using the giant constructor, a map of sorts ? Hopefully I am being clear enough, if not, I will provide more details.
Upvotes: 5
Views: 2119
Reputation: 140525
I think the greatest problem here is the fact that you have 11 parameters of the same type, and absolutely no help from the compiler when mixing them. In order to address part, what about:
public class AValue {
public final double val;
public AValue(double val) { this.val = val; }
}
and then, ugly, but (maybe?) useful: copy that 10 more times to end up with 11 classes for AValue up to KValue.
Then you can put down your constructor as
public Foo(AValue a, BValue b, ... and so on) {
That allows for a clean, compiler supported interface to build Foo.
And it doesn't mean that Foo has to store 11 objects; it could just push them into some double array that has 11 slots. Of course, you could also add type safe methods like
AValue getA()
for your Foo class.
And beyond that, you could even turn to Nicolas answer and to this:
interface ValueType { public double getValue(); }
class AValue implements ValueType {
...
@Override
double getValue() { return value; }
with
public class Foo {
public Foo(AValue a, BValue b, ... KValue k) {
this((ValueType) a, ..., (ValueType) k);
}
Foo(ValueType... values) {
... push values into double[]
Upvotes: 1
Reputation:
The main danger is that one of the users of the object would mix up the arguments, passing value for A where B is.
The answer depends on exact circumstances.
If those objects are a bunch of singletons initialized from some data source such as config file or database table, then you need to pass an interface to the constructor:
interface FooData {
double getA();
...
}
then implement that interface over table or config file.
If the objects are created on the fly based on immediate state, then some combination of Factory and Builder pattern is in order. Factory pattern to factor out common sets of values, if any (e.g. A can only be 1.0 or 0.0). Builder to make mistakes harder.
In the second case, behind factory and builder, the object would still have the 11-arguments constructor, just hidden from the outside world.
Upvotes: 1
Reputation: 44995
You could use a varargs
of double
as parameter of your constructor and check its size to ensure that it is the expected one.
Something like:
public class Foo {
private double A;
private double B;
...
private double K;
public Foo(double... coordinates) {
if (coordinates == null || coordinates.length != 11) {
throw new IllegalArgumentException("Unexpected size of coordinates");
}
this.A = coordinates[0];
this.B = coordinates[1];
...
this.K = coordinates[10];
}
...
}
This way you have only one parameter defined in your constructor but you can still provide 11
values for the sake of simplicity as next:
Foo foo = new Foo(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0);
And you can still provide it as an array
of double
as next:
Foo foo = new Foo(new double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0});
Upvotes: 3
Reputation: 3507
If the caller of the constructor needs how to set the 11 tightly bound parameter in a consistent way I would use such a constructor or maybe as already said with an Array
or a List
.
If you have or assume a problem with the consistency of this 11 parameters then I would prefer creating Foo
s with a Factory
. If this Factory uses a constructor with 11 parameter or 11 calls of a set method is up to you and your wishes of the design of this class.
Instead of a Factory class you may use different constructors with other params and have the logic for setting the 11 parameters within these different constructors.
Upvotes: 1