Flying Swissman
Flying Swissman

Reputation: 803

Constructor requiring many input arguments

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

Answers (7)

ARM
ARM

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

Neeraj Jain
Neeraj Jain

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:

  1. Initialization is indeed split across 3 lines. This means that the object is in constant state when all 3 lines are completed and in not consistent state before that.
  2. The object is indeed mutable: values that it calls may be changed by invoking of setter.

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

Adrian Shum
Adrian Shum

Reputation: 40036

Both way you suggest will work, but both with some drawbacks:

  1. 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.

  2. 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

cigno5.5
cigno5.5

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

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

Tarun Kumar
Tarun Kumar

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 :

  1. Have one Context class which has all the params as class attributes. That way, you will have just one constructor parameter.

  2. 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

lightup
lightup

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

Related Questions