borgmater
borgmater

Reputation: 706

Managing class with many fields

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

Answers (4)

GhostCat
GhostCat

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

user3458
user3458

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

Nicolas Filotto
Nicolas Filotto

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

Niklas P
Niklas P

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 Foos 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

Related Questions