Reputation: 5660
Lets assume a class Foo
with 2 instance variables, int x and int y. The use case demands I can construct the class with either none, single or all params.
input X input Y
0 0 no constuctor
0 1 public Foo(int x);
1 0 public Foo(int y);
1 1 public Foo(int x, int y);
Now whats the convention/best practices in this case. Do I need to add all the permutations of constructors ? If yes, the it would result in exponential growth. If No, then whats solution ?
Upvotes: 0
Views: 251
Reputation: 2881
As @Platinum Azure says, it depends. Since you haven't said that there is a dominant use-case ...
Remember that as a class designer, we are designing for our client programmer. How clear will their code be to a third person? How would they know the meaning of
Foo foo = new Foo();
Foo foo2 = new Foo(2);
Foo foo23 = new Foo(2,3);
And what style of code you want them to follow? The "everythingononeline" style:
Foo foo = new Foo().setNumHeads(2).setNumLegs(3);
Which, when there are many things to set, can be adapted to
Foo foo = new Foo()
.setNumHeads(2)
.setNumLegs(3);
Or the traditional OO style:
Foo foo = new Foo();
foo.setNumHeads(2)
foo.setNumLegs(3);
Then, how much work do you need to do now? Do you need a builder, or is Foo
simple enough to do without (as in the above examples)?
Another way is to supply defaults:
Foo foo = new Foo(Foo.DefaultNumHeads, Foo.DefaultNumLegs, Foo.DefaultNumTails);
which works well with a few arguments, but can be error prone when there are many if the defaults are defined as int
s. So you can apply a variant of the named argument idiom. This is where some suggest a builder, as in Named Parameter idiom in Java, or
Foo foo = new Foo(Foo.DefaultNumHeads, Foo.DefaultNumLegs, Foo.DefaultNumTails);
where Foo.DefaultNumHeads
etc are defined as final
objects. By the time you get to
Foo foo = new Foo(Foo.NumHeads(2), Foo.NumLegs(3), Foo.NumTails(5));
you are writing a builder inside of Foo
.
And what style of constructor is common in the ecosystem Foo
lives in? If other classes already have similar arguments, then maybe Foo
should too.
The point about combinatorial explosion depends on what change can be expected to Foo
. We get a combinatorial explosion if Foo
is a not-well-thought-through abstraction and we go back and change Foo
again and again in violation of the Open/closed principle. Don't do it.
So, it depends.
Upvotes: 1
Reputation: 2667
Have a constructor that accepts list/array of object. Iterate over it in your constructor and set the values according to your need. I am assuming that you have setter for all the fields available in your class.
Pros: you need not write different constructors
Cons: you need to know and understand that your index or position in list/array decides which field to set.
Foo (Object[] args){
this.setX(args[0]); // have null check accordingly
this.setY(args[1]);
}
Upvotes: 0
Reputation: 54286
A common approach for this kind of case is to use the builder pattern.
The idea with the builder is that you have an intermediate object that understands the various required or optional arguments and is used to produce an appropriately constructed object. It means you only need to have the all-args constructor in your actual business object, which can greatly simplify things.
You use the builder by doing something like this:
Foo foo = new FooBuilder().withX(10).withY(25).build();
Project Lombok provides a very helpful @Builder
annotation that will take care of all this for you: See http://projectlombok.org/features/experimental/Builder.html for details.
Upvotes: 1
Reputation: 120496
Your best bet is to use the builder pattern as in
new FooBuilder().build() // Uses default values for both parameters
new FooBuilder().setX(42).build() // Uses default value for y
new FooBuilder().setY(-13).build() // Uses default value for x
new FooBuilder().setX(42).setY(-13).build() // Supplied values for both
and then your builder might look like
class FooBuilder {
public Foo build() { return new Foo(...); }
public FooBuilder setX(int x) { ...; return this; }
public FooBuilder setY(int y) { ...; return this; }
}
Upvotes: 7
Reputation: 46183
Short answer: It depends.
Longer answer: Add the ones that correspond with real use cases. If that means one with all parameters, or one with none (which sets defaults for the parameters), great. If there are common use cases for having some parameters default and some not, provide constructors for that.
Note that you cannot have multiple constructors with the same order, number, and types of parameters.
Upvotes: 2