tags:

views:

1882

answers:

7

In some of our projects, there's an class hierarchy that adds more parameters as it goes down the chain. At the bottom, some of the classes can have up to 30 parameters, 28 of which are just being passed into the super constructor.

I'll acknowledge that using automated DI through something like Guice would be nice, but because of some technical reasons, these specific projects are constrained to Java 1.4.

A convention of organizing the arguments alphabetically by type doesn't work because if a type is refactored (the Circle you were passing in for argument 2 is now a Shape) it can suddenly be out of order.

This question might be to specific and fraught with "If that's your problem, you're doing it wrong at a design level" criticisms, but I'm just looking for any viewpoints.

+1  A: 

Refactoring to reduce the number of parameters and depth of you inheritance hierarchy is pretty much all I can think of because, nothing is really going to help keep 20-something parameters straight. You're just going to have to every single call while looking at the documentation.

One thing you could do, is to group some logically grouped parameters into their own higher level object, but that has it's own problems.

Aaron Maenpaa
+1  A: 

The best solution is not having too much parameters in the constructor. Only parameters really needed in constructor, are params that are need to correctly initialize the object. You can have constructors with multiple parameters, but also have a constructor with only the minimum parameters. The additional constructors call this simple constructor and after that setters to set the other params. This way you can avoid the chain-problem with more and more params, but also have some convenience-constructors.

Mnementh
+3  A: 

As you are constrained to Java 1.4, if you want DI then Spring would be a very decent option. DI is only helpful in places where the constructor parameters are services or something that does not vary during runtime.

If you have all of those different constructors due to the fact that you want variable options on how to construct an object, you should seriously consider using the Builder pattern.

Guðmundur Bjarni
The parameters are mostly services as you mentioned, and so DI is what I'd be needing. I think the Builder pattern mentioned in a couple other answers is exactly what I was hoping for.
Steve Armstrong
+8  A: 

What you probably want to do is have a Builder class. Then you would do something like this:

MyObject obj = new MyObjectBuilder().setXxx(myXxx)
                                    .setYyy(myYyy)
                                    .setZzz(myZzz)
                                    // ... etc.
                                    .build();

See page 8 and following of this Josh Bloch presentation (PDF), or this review of Effective Java

Michael Myers
+15  A: 

The Builder Design Pattern might help. Consider the following example

public class StudentBuilder
{
    private String _name;
    private int _age = 14;      // this has a default
    private String _motto = ""; // most students don't have one

    public StudentBuilder() { }

    public Student buildStudent()
    {
        return new Student(_name, _age, _motto);
    }

    public StudentBuilder name(String _name)
    {
        this._name = _name;
        return this;
    }

    public StudentBuilder age(int _age)
    {
        this._age = age;
        return this;
    }

    public StudentBuilder motto(String _motto)
    {
        this._motto = _motto;
        return this;
    }
}

This lets us write code like

Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
                 .name("Spicoli")
                 .age(16)
                 .motto("Aloha, Mr Hand")
                 .buildStudent();

If we leave off a required field (presumably name is required) then we can have the Student constructor will throw an exception when a required parameter is null. And it lets us have default/optional arguments without needing to keep track of any kind of argument order, since any order of those calls will work equally well.

Eli Courtwright
Of course with static imports you never even have to "see" these "builders" at all. For example, you could have static methods name(String name) which returns a builder and Student(StudentBuilder) which returns a student. Hence Student(name("Joe").age(15).motto("I've wet myself"));
oxbow_lakes
+11  A: 

Can you encapsulate related parameters inside an object?

e.g., if parameters are like


MyClass(String house, String street, String town, String postcode, String country, int foo, double bar) {
  super(String house, String street, String town, String postcode, String country);
  this.foo = foo;
  this.bar = bar;

then you could instead have:


MyClass(Address homeAddress, int foo, double bar) {
  super(homeAddress);
  this.foo = foo;
  this.bar = bar;
}

JeeBee
A: 

Well, using the builder pattern might be one solution.

But once you come to 20 to 30 parameters, I would guess that there is a high relationship between the parameters. So (as suggested) wrapping them into logically sane data-objects probably makes the most sense. This way the data object can already check the validity of constraints between the parameters.

For all of my projects in the past, once I came to the point to have too many parameters (and that was 8 not 28!) I was able to sanitize the code by creating a better datamodel.