views:

641

answers:

9

In general, what is the maximum number of parameters a class constructor should accept? I'm developing a class that requires a lot of initialization data (currently 10 parameters). However, a constructor with 10 parameters doesn't feel right. That leads me to believe I should create a getter/setter for each piece of data. Unfortunately, the getter/setter pattern doesn't force the user to enter the data and without it characterization of the object is incomplete and therefore useless. Thoughts?

+21  A: 

With that many parameters, it's time to consider the Builder pattern. Create a builder class which contains all of those getters and setters, with a build() method that returns an object of the class that you're really trying to construct.

Example:

public class ReallyComplicatedClass {
    private int int1;
    private int int2;
    private String str1;
    private String str2;
    // ... and so on
    // Note that the constructor is private
    private ReallyComplicatedClass(Builder builder) {
        // set all those variables from the builder
    }
    public static class Builder {
        private int int1;
        private int int2;
        private String str1;
        private String str2;
        // and so on 
        public Builder(/* required parameters here */) {
            // set required parameters
        }
        public Builder int1(int newInt) {
            int1 = newInt;
            return this;
        }
        // ... setters for all optional parameters, all returning 'this'
        public ReallyComplicatedClass build() {
            return new ReallyComplicatedClass(this);
        }
    }
}

And in your client code:

ReallyComplicatedClass c = new ReallyComplicatedClass.Builder()
        .int1(myInt1)
        .str2(myStr2)
        .build();

See pages 7-9 of Effective Java Reloaded [pdf], Josh Bloch's presentation at JavaOne 2007. (This is also item 2 in Effective Java 2nd Edition, but I don't have it handy so I can't quote from it.)

Michael Myers
If you do use the builder pattern, it's also an opportunity to use final fields on the resulting object.
Jason S
+2  A: 

i would suggest to find dependencies between the parameters and then create structures or otherwise classes to keep those and pass them to your constructor instead of a bunch of things that don't seem related at first glance.

Konstantinos
+10  A: 

You can decide when enough is enough and use Introduce Parameter Object for your constructor (or any other method for that matter).

Jason Punyon
But make sure you're not just moving the complexity from one place to another: what will the constructor for the Parameter Object holding 10 parameters look like? Will you need a Parameter Object for your Parameter object? ;-)
bendin
@bendin: I'm just sayin' what's out there man. Both bad and good code can be written with it. :)
Jason Punyon
+6  A: 

Code Complete 2 recommends a fairly sensible limit of seven parameters to any method.

Try to establish sensible default values for some of the members. This will let you use getter/setters without worrying that the characterization is incomplete.

GrahamS
I've also added that rule to my religion from Code Complete.
Robert Gould
A: 

I'd usually say no more than five, from the 7+/-2 rule of short term memory, and some pessimism about programmer attention spans. Note: I'd count a varargs list as one entity.

If you really are constrained to construct the object in one go, you can usually collect related parameters in simple value objects and pass those into the constructor. Try to ensure that the value objects make some conceptual sense and are not just random collections of information...

Pontus Gagge
A: 

How about passing in a Param => Value Map object to the constructor? If the caller omits any critical params, have the constructor toss an Exception.

It means bad calls to the constructor will only be caught at runtime instead of compile time, which is a downside. But a getter/setter approach has the same problem, and this should be much easier to work with.

BlairHippo
A: 

I would need to know more that what the class does and what the parameters are, but there is a possibility that the class has too many responsibilities. Would it be possible to split the class to smaller independent classes?

Using setters does not solve the problem of the class having many dependencies/parameters. It just moves the problem to a different place and does not force the parameters being entered.

For methods, I try to follow the advice from the Clean Code book to have no more than 3 parameters per method (IIRC). For constructors I may have more parameters, because typically the constructor will be called by my dependency injection framework and not by me.

The builder pattern mentioned by mmyers is also a good solution when building complex objects, and there is no way to make them less complex.

Esko Luontola
A: 

It depends.

If some parameters are of the same type and can be mixed up, I'd tolerate a rather small number (say 5).

If the parameters are of different types, so they cannot be mixed up, then I'd tolerate some more. Ten would be close to the limit, though.

starblue
+1  A: 

I don't think you can say that an appropriate number is "seven, no more" or "five".

A good rule of thumb for constructors is to pass an object its identity, not its state. Those parameters you pass in are ones that are essential for the existence of the object, and without which most operations of the object may not be possible.

If you genuinely have a class with a very complicated natural identity, hence requiring many parameters then consider the design of your class.

An example of a bad constructor is:

public NightWatchman(int currentFloor, int salary, int hapiness) {...}

Here the NightWatchman is being constructed with some default values that will almost certainly change in a short time. It seems funny that the object is told about their values one way, and then has them in a different way (via their setters) in future.

An example of a better constructor is:

public GateWatchman(Gate watchedGate, boolean shootOnSight) {...}

The gate the watchman is watching is required information for one to exist. In the class I would mark it private final. I've chosen to pass the shootOnSight variable into the constructor, because here it was important that at all times the object knew whether to shoot burglars. Here, identity is being used as type.

I could have a class called ShootingGateWatchman and PoliceCallingGateWatchman - i.e the parameter is interpreted as part of the objects identity.

jgubby