Reputation: 803
My question concerns constructors in java. I've learnt that we should minimize the number of arguments to method including constructor. So if I have a class with requires a lot of input arguments to be created how do I best go about this. Should I
A) Include them all in the constructor method signature:
Example:
public MyClass(SomeThing A, Vector v, OtherThing B, int number.. etc.){
// construct
}
..
MyClass c= new MyClass(..);
c.doSomethingWithAllYouGot();
B) Can I construct only very little and then require the object user to add things before calling specific methods
public MyClass(SomeThing A){
// construct
}
..
MyClass c=new MyClass(A);
c.attributeVector(v);
c.connectTo(B);
c.setNumber(n);
// etc.
c.doSomethingWithAllYouGot();
The second variant seems more elegant and clean but allows for more errors if the class is incorrectly used.
Or is there a problem with the the design of the class if it has too many input arguments?
Upvotes: 4
Views: 3537
Reputation: 11
If the object's variables are all related to it then it can have as many variables in the constructor as necessary.
Consider that not all the variables may be known/may be null when the object is created. So rather than passing an empty value to the constructor, just instantiate within the constructor without a parameter. E.g.
public Student (String firstName, String lastName)
{
this.firstName = firstName;
this.lastName = lastName;
this.grade = 0;
this.report = "";
}
Note: Of course you would also have constructor(s) when you do know those values when you instantiate the object.
Upvotes: 0
Reputation: 7730
Source Effective Java
The problem of constructors is that they are not flexible. Our example has only 5 parameters. But think about real world when class Person has probably 20 or more field. In this case creating of such object is pretty verbose.
In real world where a class can have optional Attribute as well as Mandatory Attibute
In this case you will probably want to create several overloaded constructors with different number of parameters. To avoid dupplicate assignemnt code it is common technique to use so called telescopic constructors, i.e. pattern when constructor invokes other constructor. This pattern is good but in some too verbose and hard for modifications.
Now Another alternative is Bean Pattern
but it has it's own disadvantage
Lets take an example of Simple Bean
class Person {
private String firstName;
private String lastName;
public String getFirstName() {return firstName;}
public void setFirstName(String firstName) {this.firstName = firstName;}
public String getLastName() {return lastName;}
public void setLastName(String lastName) {this.lastName = lastName;}
}
You create the instance with
Person president = new Person();
p.setFirstName("George");
p.setLastName("Bush");
As you can see:
This why why builder pattern come in lime light which combines the safety of the telescoping constructor
pattern with the readability of the JavaBeans pattern
.
Upvotes: 0
Reputation: 40036
Both way you suggest will work, but both with some drawbacks:
The argument list of constructor is too long, it usually make it hard to maintain. For example, if you are expecting to pass in 5 strings, it is almost impossible for the user to know what to pass without consulting documents.
It works in a lot of case but if internal state consistency is important, or if you want to make your object immutable, this is probably not a good idea.
There are other common solutions
Fluent builder, so the code will look like:
MyClass c=new MyClassBuilder(A)
.withAttributeVector(v);
.connectTo(B);
.withNumber(n)
.create();
so the complicated unintuitive constructor call can be hidden in the builder.
Use an object as input parameter:
public MyClass(MyClassConstructParam p){
}
..
MyClassConstructParam p=new MyClassConstructParam();
p.attributeVector(v);
p.connectTo(B);
p.setNumber(n);
MyClass c=new MyClass(p);
Upvotes: 3
Reputation: 712
In my honest opinion having a lot of constructors or constructors with a lot of parameters probably turns in a mess.
You should considering the builder pattern as @TJ suggested but on the other hand you should think to reduce parameters in constructor to the minimum set. This set could be the essential parameters, maybe data which doesn't change during the time.
Of course, if all parameters are required and they have to be put into object as it is just created you should have them in constructor.
Upvotes: 0
Reputation: 978
If there are really that many parameters, it could that your class is trying to be too many things at the same time. Take this as a hint that it could be broken down into smaller classes.
Alternatively, you could make the constructor package private, and use a builder in the same package to instantiate it.
Upvotes: 3
Reputation: 5230
In second approach, what if setters are not called after instantiating the class? Your instance will be in in-consistent state.
There are two ways to handle this :
Have one Context class which has all the params as class attributes. That way, you will have just one constructor parameter.
Use builder pattern. Create a builder class. In builder class's constructor, call your class's constructor and in build methods calls setters. Also, make sure that you make constructor of your class private.
Upvotes: 0
Reputation: 674
I depends on what you think the class basically needs
If "SomeThing A" is something the class cannot do without - include it as paremeter in the main constructor while "Otherthing B" if not fundamental can be added as a default that can be set via other methods
Upvotes: 0