Saturday, July 11, 2009

Introducing the Builder Design Pattern

Static factories and constructors have limitations when dealing with objects with large numbers of optional parameters.

A classic solution is to use multiple constructors. The first constructor will have only the required parameters. The second one, the required parameters and a single optional parameter. The third one, the required parameters and two optional parameter and so one until the last optional parameter. The problem with this solution is that you can easily invert two parameters when constructing the object.

Another solution is to use the JavaBean pattern, in which you call the paramterless constructor and call the setter methods to populate your objects. The problem with this pattern is that you cannot enforce consistency. Your objects may be in an inconsistent state if you do not set the required parameters.

A third solution is to use the builder design pattern.

Here's an interesting implementation of this design pattern described by Joshua Bloch in the book 'Effective Java Second Edition' (which is, by the way, a book to put in every programmer hands).

The client calls a constructor with all the required parameters and gets a builder object. Then the client calls methods on the builder object to set each optional parameters. Finally the client calls a build method which generate an instance of the object which is immutable. Immutable objects have a lots of benefits and may be very useful.

public class Customer {

private final String name;
private final String surname;
private final int age;
private final String address;
private final String email;

public static class Builder {

//Mandatory parameters
private String name;
private String surname;

//Optional parameters
private int age;
private String address;
private String email;

public Builder(String name, String surname) {
this.name = name;
this.surname = surname;
}

public Builder age(int val) {
age = val;
return this;
}

public Builder address(String val) {
address = val;
return this;
}

public Builder email(String val) {
email = val;
return this;
}

public Customer build() {
return new Customer(this);
}
}

private Customer(Builder builder) {
name = builder.name;
surname = builder.surname;
age = builder.age;
address = builder.address;
email = builder.email;
}
}

A good practice is to check the invariants in the build method and send an IllegalStateException if one of the attribute is invalid. This way, you will always be sure that your object is valid after being instantiated.

Here's how the client code looks :

Customer customer = new Customer.Builder("John", "Doe").age(25).email("johndoe@gmail.com").build();

The result is a client code easy to write and read.

Resources : To mutate or not to mutate ?

17 comments:

  1. But you will have to type a lot of duplicated parameters...does IDE have the Design Pattern generator for this?

    ReplyDelete
    Replies
    1. That's a great IDEA, might be IntelliJ already have that ? By the way here is another example of Builder design pattern in Java

      Delete
  2. Why not just put the fluent methods in the Customer class?

    ReplyDelete
  3. what is wrong with old plain constructor?

    ReplyDelete
  4. The problem with a plain old constructor is that if you have too many parameters to fill, it becomes very unreadable as what parameter is what.

    The reason I understand to use the Builder patterns is when you need to create a bean and you need to synchronize all of your parameters at once or do something else critical with the properties. As mentioned, you need the state of the bean to be consistent.

    If it doesn't have to maintain this consistency, I also like to throw in this option:

    Customer customer = new Customer("John", "Doe") {
    setAge(25)
    setEmail("johndoe@gmail.com");
    };

    I love the interface of the Builder pattern, I just hate the extra boilerplate code.

    ReplyDelete
  5. iy's not a builder pattern. it's a java code.

    ReplyDelete
  6. I don't like boilerplate code too. If you have simple objects keep it simple. The main advantage of this pattern is to create immutable objects which can be very handy in multi-threaded environment.

    ReplyDelete
  7. And checking the invariants in the build method will ensure the validity of your objects.

    ReplyDelete
  8. What's the problem with constructing new customer following plain, old, easy, primitive, readable, layman, amateur way?

    Customer customer = new Customer();
    customer.name("John", "Doe");
    customer..age(25);
    customer.email("johndoe@gmail.com");

    Looking at your code it took me 5min to notice that all what that fancy code is doing is just to construct object.

    It took me another 15min to understand convoluted approach to such simple thing.

    Design patterns are from hell. Programming by its nature is logical, and logic is science about relations between the concepts naturally occurring in human mind, design patterns are gift from hell to destroy that science by introducing unnatural, artificial concepts and under the pretense of bringing the order bringing in chaos instead.

    I hit this blog just accidently when I googled "design patterns sucks" to went my frustration with configuring jboss server which is based on that crap.

    ReplyDelete
    Replies
    1. Amen. Builders are often a pain in the neck. 1.) the doA().doB().doC().LookHowCleverIAmDoingEverythingOnOneLine() style makes stepping through code difficult and, 2.) if standard getters are not included in the base object the object can't be modified after the builder is called (I get that this is part of the whole point of using a builder, but often this kind of requiring a set of fields to be defined at once is not helpful). Just use a constructor and getters and setters.

      Delete
  9. M - The problem using object.field = value, or object.setField(value) statements after object creation, is that your object might be in an inconsistent or invalid state between initial instantiation and the rest of the object's "setup". Using a builder, you have an atomic object creation process: either you have a good, consistent object or you have no object.

    ReplyDelete
  10. I've been looking for info on Introducing the Builder Design Pattern and luckily I ran into your blog, it has great info on what I'm looking and is going to be quite useful for the paper I'm working on.
    BTW is crazy how many generic viagra blogs I manage to dodge in order to get the right site and the right information.

    ReplyDelete
  11. To be honest, I don't think the sample code display Builder pattern. It's more like Fluent Interface (http://martinfowler.com/bliki/FluentInterface.html)

    The Builder is kind of Factory, but it produces more than one kind of "product", and usually the ones which are complex to create as usual.

    ReplyDelete
  12. Wearing the development cap and also actively enjoying the role of your common service provider like Contractors Long Island is a severe selection that can at some point expose technical needs, problems and tiring commitments.

    ReplyDelete
  13. Your implementation looks more like a FluentInterface. Here is an example of Builder pattern using C#
    http://www.nileshgule.com/2012/08/builder-design-pattern.html

    I did not find the "Director" in your imeplementation which I think is the heart of Builder pattern.

    Correct me if I am wrong

    ReplyDelete
  14. I invite all the nice folks who say that a many-arg-constructor contributes to unreadability to write a POJO with all the Builders inside, enforcing the different possibilities of integrity, and than put both next to each other.... Builders not only create a LOT of overhead, if there are indeed many arguments, there will also be many different possibilities. When you're done implementing that you'll need a dozen test cases just to ensure your builders work... My XP is: builders are a cool idea but practically they bring many many downsides to maintenance and particularly readability. I predict they will not last the JAVA world very long. That's just my xp after having seen many come and go in 20 years of ICT work... May I furthermore kindly point to something: Steve Jobs was a man admired by many. What made him so respected, successful and aside, very rich, was that he did not just interpreted and implemented the ideas of people who wrote a book, say "Effective Java" despite the fact that the whole world read it and agreed it was the way to go, but that he had the balls to simply say to the whole world: that and that and this and that is crap and I simply won't do it. And he wrote his own book.. My point is NOT: "Effective Java sucks". It is, read it but dare to question certain aspects of books in general if your hand-on experience tells you that certain things are not as ingenious as they are sold... Respect to all.

    ReplyDelete
  15. I like your post very much. It is very much useful for my research. I hope you to share more info about this. Keep posting java certification course

    ReplyDelete