30

Is it wrong to have a lot of parameters inside a constructor? Like 10 to 15 parameters? Because I was designing a class where a constructor will have lots of parameters, for example, a Person class.

My example person class has 6 parameters in its constructor:

public class Person {
    private String fName;
    private String lName;
    private String mInitial;
    private int age;
    private String contactNumber;
    private String emailAddress;

    public Person(String fName, String lName, String mInitial, int age, String contactNumber, String emailAddress) {
       //insert rest of code here 
    }
}

Is that wrong? Creating lots of parameters for a constructor?

Then I am planning to create a class named Employee, then extending it to person class, then it will have a long constructor as well.

The thing that worries me about is the practice, is this good or what? Any other suggestions?

chrki
  • 6,143
  • 6
  • 35
  • 55
KyelJmD
  • 4,682
  • 9
  • 54
  • 77
  • Shameless plug: See also http://stackoverflow.com/questions/2432443/best-practice-for-passing-many-arguments-to-method/2432539#2432539 – JRL Nov 01 '11 at 04:37

4 Answers4

32
  1. In general, if you find yourself have too many parameters, that means you don't have enough low-level classes. In your case, you could have a class Name { /* fname, lname, initial, */ } and perhaps a class Contact { /* email, phone */ }

  2. When you extend your class, have the constructor take the base as one parameter, and then add the new extra parameters. (You probably mean Employee will extend Person, rather than vice versa, so public Employee (Person person, Company company, String employeeId) { super(person); this.company = company; this.employeeId = employeeId; }

Good question!

necromancer
  • 23,916
  • 22
  • 68
  • 115
  • both, is there any code that I can see for actual implementation with a main class on it? – KyelJmD Nov 01 '11 at 10:14
  • 4
    i would be doing you a disservice by spoon feeding code "with a main class on it", since it seems like you are trying to learn programming. the most important step in learning is to think hard. for point 1. your constructor would change FROM the existing: `public Person(String fName, String lName,String mInitial,int age,String contactNumber,String emailAddress) { /* ... */ }` TO this: `public Person(Name name, int age, ContactInfo contactInfo) { /* ... */ }` and you would need `class Name { private String fName; private String lName; /* etc. */ }` and similarly `class ContactInfo` continued – necromancer Nov 01 '11 at 22:15
  • for point 2. think really hard about whether Employee extends Person? or Person extends Employee? the right answer is Employee extends Person because all Employees are Persons but NOT all Persons are Employees. once you understand that, what i am suggesting is to create `class Employee extends Person { private String employeeId; private String companyName; public Employee (Person person, String employeeId, String companyName) { super(person); this.employeeId = employeeId; /* ... */ } }` and make sure `class Person` ALSO has a constructor: `public Person (Person other) { /* copy fields */ }` – necromancer Nov 01 '11 at 22:23
  • hopefully you know what `super(person);` does above ... it will call the constructor of the base class: `Person` Good Luck! – necromancer Nov 01 '11 at 22:25
  • does this means that super(person) you are calling the constructor of the base class (in this case class person) am I right? from the looks of it it looks like a has a relationship am I right? – KyelJmD Nov 03 '11 at 03:28
  • yes, you are calling the constructor of the base class which would have 2 constructors: 1: `public Person (Name name, int age, ContactInfo contactInfo) { this.name = name; this.age = age; /* ... */ };` and 2: `public Person (Person other) { this.name = other.name; this.age = other.age; /* ... */ }` – necromancer Nov 03 '11 at 04:50
  • 3
    HOWEVER, in the programming community this is NOT a "has a" relationship; instead it is a "is a" relationship. That is, "Employee is a Person". When you call `super(person);` you are using the "is a" relationship and not "has a". BUT internally programming languages implement "is a" and "has a" in a similar way -- both are internally "has a" relationship. So your intuition is right, but your terminology is not. The language-level (non-internal) difference is that an "is a" relationship lets you assign a derived object to a base reference, and use polymorphism when you call methods later – necromancer Nov 03 '11 at 04:51
15

Instead of using telescoping constructor pattern, use builder pattern

public class Person {
    private final String fName;
    private final String lName;
    private final String mInitial;
    private final int age;
    private final String contactNumber;
    private final String emailAddress;

    public Person(PersonBuilder builder) {
       //insert rest of code here 
       fName = builder.fName;
       ...
    }

    public static class PersonBuilder {
        private String fName;
        private String lName;
        private String mInitial;
        private int age;
        private String contactNumber;
        private String emailAddress;
        // setter methods
        public PersonBuilder setFirstName(String name) {
             fName = name;
             return this;
        }
        ...
        // build method
        public Person build() {
            return new Person(this);
        }

    }
}

...

Person p = new PersonBuilder()
              .setFirstName("")
              // set all the setter methods
              .build();
Prince John Wesley
  • 62,492
  • 12
  • 87
  • 94
  • builder pattern? how is that? ? – KyelJmD Nov 01 '11 at 04:24
  • @user1023060: follow the template link – Prince John Wesley Nov 01 '11 at 04:25
  • "Person p = new PersonBuilder()" I thought you cannot assign variables that have different types, isn't Person has a different type? compared to PersonBuilder? – KyelJmD Nov 01 '11 at 04:43
  • @user1023060: you need to build it like this: `new PersonBuilder().setFirstName("prince").setLastName("John Wesley").setAge(23).setInitial("R").build();` – Prince John Wesley Nov 01 '11 at 04:46
  • can I see the full set? with a main class? I can't seem to grasp the idea – KyelJmD Nov 01 '11 at 04:52
  • @user1023060: write all the setter methods like `setFirstName()` and assignment in constructor and build(i mean the `new ... build()` call ) it in `main()` method – Prince John Wesley Nov 01 '11 at 04:54
  • 10
    Using a builder is useful only if most of the constructor arguments are optional. If he wants to use all 7 params, the builder will not help to reduce clutter. Ideally, he should be using composition. – Sahil Muthoo Nov 01 '11 at 04:58
  • 2
    Uhmm in my case, the parameter are not optional, they are needed, it's more of a requirement – KyelJmD Nov 01 '11 at 05:00
  • @user1023060: No parameter reordering issue in this pattern – Prince John Wesley Nov 01 '11 at 05:04
  • but it looks messy and on the plus side I'll use a inheritance, thus leading it to more parameters in the next class. – KyelJmD Nov 01 '11 at 05:19
  • to know about builder patterns refer effective java . Builder patterns are really great avoid confusion when somebody works on code and with telescopic patterns one might end up using wrong constructor – akshay_shahane Jun 08 '17 at 14:48
10

You could decompose Person into Name and Contact.

public class ComposedPerson {
    private Name name;
    private int age;
    private Contact contact;

    public ComposedPerson(Name name, int age, Contact contact) {
        this.name = name;
        this.age = age;
        this.contact = contact;
    }

    public static void main(String... args) {
        Name name = new Name("John");
        Contact contact = new Contact("12345", "john@doe.com");
        ComposedPerson person = new ComposedPerson(name, 45, contact);
   }

Sample Name. See how I use a telescoping constructor to allow for optional arguments.

public class Name {
    private String fName;
    private String lName;
    private String mInitial;

    public Name(String fName) {
        this(fName, null, null);
    }

    public Name(String fName, String lName) {
        this(fName, lName, null);
    }

    public Name(String fName, String lName, String mInitial) {
        this.fName = fName;
        this.lName = lName;
        this.mInitial = mInitial;
    }
} 
Sahil Muthoo
  • 12,033
  • 2
  • 29
  • 38
6

Yes it is not good to have many parameters in any kind of functions. Maximum parameters should be around 7, according to a book named Code Complete 2.

It is because it will decrease the code readability and maintainability and usability. Imagine other developers working on the same project, how to follow your code?

There are lots of different ways to handle this, factory pattern, for example. It depends on how you design your application.

But in your code, I think it is ok that the no. of parameters is still acceptable (6 parameters)

If your object require so many parameters to instantiate, then you need to rethink how you design your code. For example, can some of the attributes wrap into a separate class? can some of the attribute not necessary pass as a parameter? i.e., get the value from the other class. etc...

TheOneTeam
  • 25,806
  • 45
  • 116
  • 158
  • what's the best way to solve this dillema of mine? since I'll be making another class named Employee and extending it to this person class?? thus adding more parameters to a constructor, is there any efficient way to do this? – KyelJmD Nov 01 '11 at 04:23
  • @KyelJmD You could create a constructor in the Person class that accepts a Person as a parameter. That way in the Employee class, you can have a constructor that accepts a Person parameter (and passes it via super), and the rest of the Employee-specific parameters. – Kartik Chugh Mar 02 '17 at 14:17