Question

Following are the two approaches:

  • constructor with all the class properties

Pros: I have to put an exact number of types of parameters so if I make an error the compiler warns me (by the way, is there a way to prevent the problem of having erroneously switched two Integer on the parameter list?)

Cons: if I have lots of properties the instantiation line can become really long and it could span over two or more lines

  • setters and the default empty constructor

Pros: I can clearly see what I'm setting, so if I'm doing something wrong I can pinpoint it as soon as I'm typing it (I can't make the previuos error of switching two variables of the same type)

Cons: the instantiation of an object with lots of properties could take several lines (don't know if this is really a con) and if I forget to set a property the compiler doesn't say anything.

What will you do and why? Do you know of any light pattern (consider that it should be used everytime an object wth 7+ properties is instantiated) to suggest? I'm asking this because I tend to dislike large constructors where I can't figure out fast where is the variable I'm looking for, on the other hand I find the "set all properties" vulnerable to missing some of the properties.

Feel free to argument my assumptions in pros and cons as they are only mine thoughts :)

Update - a question I've found which is related to this: Building big, immutable objects without using constructors having long parameter lists

Was it helpful?

Solution

You might look at the Builder pattern advocated by Joshua Bloch, and described in Effective Java. There's a presentation with the main points at http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2689.pdf; no doubt you could dig up a better reference.

Basically, you have another class, probably an inner class, which provides methods named after the properties being set, and which return the original builder so you can chain calls. It makes for quite a readable chunk of code.

For example, let's suppose I have a simple Message with a few properties. The client code constructing this could use a builder to prepare a Message as follows:

Message message = new Message.Builder()
    .sender( new User( ... ) )
    .recipient( new User( ... ) )
    .subject( "Hello, world!" )
    .text( messageText )
    .build();

A fragment of Message.Builder might look similar to the following:

public class Builder {

    private User sender = null;
    // Other properties

    public Builder sender( User sender ) {
        this.sender = sender;
        return this;
    }
    // Methods for other properties

    public Message build() {
        Message message = new Message();
        message.setSender( sender );
        // Set the other properties
        return message;
    }

}

OTHER TIPS

You've missed the biggest pro of having a constructor with loads of parameters: it lets you create immutable types.

The normal way of creating immutable types without huge constructor nastiness is to have a helper type - a builder which maintains the values you'll want in your final object, then builds the immutable object when you're ready.

Recent academic research (CMU and Microsoft) on API usability suggests that default constructors with setters would be the way to go in terms of usability. This is from "Usability Implications of Requiring Parameters in Objects' Constructors" by Jeff Stylos and Steven Clarke and was presented at the International Conference on Software Engineering:

Abstract: The usability of APIs is increasingly important to programmer productivity. Based on experience with usability studies of specific APIs, techniques were explored for studying the usability of design choices common to many APIs. A comparative study was performed to assess how professional programmers use APIs with required parameters in objects' constructors as opposed to parameterless "default" constructors. It was hypothesized that required parameters would create more usable and self-documenting APIs by guiding programmers toward the correct use of objects and preventing errors. However, in the study, it was found that, contrary to expectations, programmers strongly preferred and were more effective with APIs that did not require constructor parameters. Participants' behavior was analyzed using the cognitive dimensions framework, and revealing that required constructor parameters interfere with common learning strategies, causing undesirable premature commitment.

You mention it in your post, but I think this is an important point that deserves more attention: unless every input parameter is a different type, the big problem with huge constructors is that it's very easy to transpose a couple of variables. The compiler is an unreliable safety net -- it will catch some mistakes, but the ones that slip through are going to be much more difficult to identify and debug. Especially because the input list for a huge constructor is quite opaque unless you've got the API open in another window.

Getters and setters are vastly easier to debug, especially if you institute safeguards that throw a runtime exception if the object isn't properly populated. And I'm a huge fan of "easy to debug."

Prior to this thread I'd never heard of the Builder pattern Rob mentions. Never used it myself (obviously), but it's damned intriguing.

I prefer taking constructor arguments, for the aforementioned immutability reasons. If that gives you a constructor that takes lots of arguments (say more than four or so), that's a code smell to me: some of those arguments should be bundled together into their own types.

For example, if you have something like this:

class Contact
{
    public Contact(string firstName, string lastName, string phoneNumber,
        string street, string city, string state, int zipCode) { ... }
}

I'd refactor it to:

class Contact
{
    public Contact(Person person, PhoneNumber number, Address address) { ... }
}

class Person
{
    public Person(string firstName, string lastName) { ... }
}

class PhoneNumber
{
    public PhoneNumber(string digits) { ... }
}

class Address
{
    public Address(string street, string city, string state, int zipCode) { ... }
}

Too-large classes are a really common design problem in OOP codebases.

There are other aspects as well. If you want to be able to certain things with your class at design time rather than just at runtime, for example adding your class as an object in the Object Palette (this is Java using Netbeans) you need to provide a no-argument constructor in order to be able to do so.

There are other strategies here, too. Before trying to figure out how to deal with lots of parameters, I think it is important to re-visit your design and look at whether your class is doing too much. See if you can group some of the parameters together into a new class, and move some behavior into that class.

setters and the default empty constructor

JRL obliquely touched on it, but one reason to consider using setters is to have the object conform to the JavaBean specification. This makes instances amenable to editing via introspection tools and persistence using certain serialization techniques.

Who says you can't do both? I'd say mandatory properties go into the constructor, optional ones are handled with setters. BTW, who says you always need one setter per property? If two properties belong together conceptually, why not set them together?

I like the Builder pattern too, but the most important rule is: always use your brain and find the design that best fits the specific problem. There's no one-size-fits-all solution.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top