In Defence of the Builder Pattern

There was an interesting discussion on reddit about this blog post by Robey Pointer. First off and before I start my defence of the Builder pattern I should say that it’s a really good article and that everyone should read it. The author states that patterns are boilerplate to your code since they good ones are absorbed into languages as they develop. In an ideal world that might be true but given the glacial pace of language evolution (closures in Java anyone?) it’s also pretty unlikely to happen even in a post java world. Whether or not they they are absorbed into the language does not detract from the fact that they represent smart solutions to common problems.

The article essentially slates the Factory and Builder patterns in the Java language, two of the most common creational patterns. To be honest, I have to agree with the Factory pattern criticism but I completely disagree with the comments made about the Builder pattern. Robey makes some great points about how they could be replaced by configuration classes (I think that default parameters would solve most of these issues). What I think is missed is the usefulness of the Builder pattern for creating complex objects (the GoF book explicitly states that Builders deal with the “construction of a complex object”), especially when you need to do this repeatedly such as when writing unit tests. In fact I kind of think of this as a natural extension of the Null Object Pattern which has grown up and become a Default Object Pattern.

As I mentioned above, I think that complexity is the aspect of the code that makes the case for using a Builder over anything else. I’ve seen some devs use Builders to create immutable objects but I think that this is not a great usage or the pattern. Given that this pattern is only really suited to the creation of complex objects, a useful example needs to be complex enough to proof the point but simple enough to easily follow so apologies if I have chosen something that you think is too simple/complex.

Lets say we have a Person class. This class is fairly complex in that it has nested objects inside it (addresses, cars, pets) as well as some simple ones (firstName, lastName).

package com.bloodredsun;

import java.util.List;

public class Person {

    private String firstName;
    private String lastName;
    private List <Address> addresses;
    private List<Car> cars;
    private List<Pet> pets;

    public Person(String firstName, String lastName,
                          List<Address> addresses,
                          List<Car> cars, List<Pet> pets) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.addresses = addresses;
        this.cars = cars;
        this.pets = pets;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public List<Address> getAddresses() {
        return addresses;
    }

    public List<Car> getCars() {
        return cars;
    }

    public List<Pet> getPets() {
        return pets;
    }
}

Of course, these nested objects such as Address and Car could have further levels of nesting, containing further objects.

Part of the hypothetical application that uses the Person object involves processing them and since we are good little test infected developers, we want to make sure we have tests that tell us what happen and that we pass our acceptance criteria. Now creating objects via constructors, or worse yet setters, would give us code that dwarfed the test code. Every time we wanted to create another test, we would have to go through the same rigmarole of setting up the objects. We could create static methods to create the object but hey, that’s a Factory pattern! Code reuse would be a pain too since the slightest difference would require another method, not good.

What we need is a method of creating the object that allows it to have default values while still allowing us to easily override them, and preferably with a fluid interface. Step forward the Builder pattern.

package com.bloodredsun;

import java.util.Collections;
import java.util.List;

public class PersonBuilder {

    private String firstName;
    private String lastName;
    private List<Address> addresses;
    private List<Car> cars;
    private List<Pet> pets;

    public PersonBuilder() {
        this.firstName = "Bob";
        this.lastName = "Smith";
        this.addresses = Collections.emptyList();
        this.cars = Collections.emptyList();
        this.pets = Collections.emptyList();
    }

    public PersonBuilder withFirstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    public PersonBuilder withLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

    public PersonBuilder withAddresses(List<Address> addresses) {
        this.addresses = addresses;
        return this;
    }

    public PersonBuilder withCars(List<Car> cars) {
        this.cars = cars;
        return this;
    }

    public PersonBuilder withPets(List<Pet> pets) {
        this.pets = pets;
        return this;
    }

    public Person build(){
        return new Person(firstName, lastName, addresses, cars, pets);
    }
}

This means that we can write tests quickly and easily, setting up the objects with very little code. Returning the Builder allows method chaining which also makes for a nicer syntax and I know it’s personal preference but I like to use the prefix ‘with-‘ for my setters to indicate that they are something more than setters. In this example I also used further Builders within this Builder. It’s not something you have to do for simple objects (in fact I discourage it) but I wanted to show that complex objects can benefit from being constructed from nested Builders.

package com.bloodredsun;

import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;

import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

public class PersonProcessorImplTest {

    PersonProcessorImpl processor;

    @Before
    public void setup(){
        processor = new PersonProcessorImpl();
    }

    @Test
    public void shouldReturnFalseForJones(){
        Person person = new PersonBuilder().withLastName("Jones")
                                           .build();
        assertFalse(processor.process(person));
    }

    @Test
    public void shouldReturnTrueForOneCar(){
        List cars = Arrays.asList(new CarBuilder().build());
        Person person = new PersonBuilder().withCars(cars).build();
        assertTrue(processor.process(person));
    }

    @Test
    public void shouldReturnFalseForOneCarAndMoreThanOnePet(){
        List cars = Arrays.asList(new CarBuilder().build());
        List pets = Arrays.asList(new PetBuilder().build(),
                                  new PetBuilder().build());
        Person person = new PersonBuilder().withCars(cars)
                                           .withPets(pets)
                                           .build();
        assertTrue(processor.process(person));
    }

Now you could certainly do a lot of this setup with a good mocking library like Mockito but you would still find yourself wasting lines and lines of code setting up the object. Using the Builder pattern in this way not only makes your test code far shorter and more readable but it also makes it far quicker to write.

For a real-world example of a nested structure, at my current work we consume a Restful service which creates an object that is about 8 levels deep. This is not unnecessary complexity but an accurate reflection of the domain object. I cannot imagine trying to write tests for something as simple as a filter or a bean mapper on an object that complex without using a Builder.

One reason developers love to hate on Design Patterns is the fact that to many they represent “Cargo Cult Code” – code that appears to do the job that is written by people who don’t quite understand what they are doing and just lower the signal-to-noise ratio. That crappy code is written in the name of design patterns does not change the fact that they are still what they were described to be by Gamma et al, “simple and elegant solutions to specific problems in object-oriented software design”.

7 thoughts on “In Defence of the Builder Pattern

  1. JamesR

    Your “defense” – not that any is needed, might have carried some more weight if the tests you used to demonstrate your ‘argument’ were actually any good.

    Naming “PersonProcessor” – Terrible name for an interface. What are the responsibilities of this object? Is it simply a predicate?

    – Naming “PersonProcessorImpl” – really? Impl really is cargo cult programming, and demonstrates that you don’t really know what your class is doing. Perhaps it should be called something like “PeopleWithCarsPredicate”

    – Naming test “shouldReturnTrue…” – this give no clue about the business domain or concept that the class is trying to test. Perhaps it should be called something like “predicateReturnsTrueForPeopleWithCars”

    – Builders can use static ‘factory’ methods rather than constructors:


    public static Builder aPerson() {
    return new PersonBuilder();
    }

    thus:


    Person person = aPerson().build()

    – Builders can take other builders, not just what they build:


    Person person = aPerson()
    .withCars(aCar())
    .withPets(aPet().withName("fluffy"));

    – You should use google guava for your collection stuff!


    List someFoos = newArrayList(aFoo());

    Reply
    1. Martin Post author

      Sorry but I think you’ve missed the point about the article. The code is there to highlight the concepts used, especially for non-experts. I hate articles that are written only for architects and senior developers. I prefer to write for everyone and this article was about the creation of complex objects. So in answer:

      PersonProcessor IS a terrible name for an interface and PersonProcessorImpl is the archetypal (and uninformatively named as you mentioned) example of an implementation but it follows conventions that everyone understands. It’s responsibility is to be a test harness for the Builder objects and nothing more. The unit tests could be better named but again, they are just examples that should be simple enough for beginners to follow and for more experienced people to ignore if it is too obvious.

      “Builders can use static ‘factory’ methods rather than constructors” – I disagree. As soon as you need a version of your object with different values, your static factory method is useless and you would have to create a new one – not very scalable – whereas with Builders you can create objects as sparse or full as you care to.

      “Builders can take other builders, not just what they build” – Yes, as the examples even include CarBuilder and PetBuilder in the last unit test except since the Person class requires Lists, they need to be wrapped in a Collection first so your example would not compile.

      “You should use google guava for your collection stuff!” – Yes, I’m a big fan of predicates and filters in guava but guess what, this article is not about predicates and filters! It’s about Builders and how useful they are when it comes to the creation of complex objects. As I even said in the article, “Given that this pattern is only really suited to the creation of complex objects, a useful example needs to be complex enough to proof the point but simple enough to easily follow so apologies if I have chosen something that you think is too simple/complex.” My examples are there to show how they can be used and not to provide the canonical representation of Builders.

      PS I am English, so I write colour, centre and defence. No need to put quote marks around your use of the word defense since I’m sure we can all work it out 🙂

      Reply
    1. Martin Post author

      Thanks Alex. I know that when creating examples it’s a difficult line to walk between creating ones that are too simplistic and ones that are more appropriate but difficult to follow but in this case, the complexity is the reason why we use a Builder.

      Reply
  2. Michael Peters

    I think the point of the original article was the Builders only exist in Java because it lacks the language features to handle building complex arguments more simply. For instance, in Perl (and Python and Ruby would be very similar) your test code would simply be:


    package BloodRedSun;
    use base 'Test::Class';
    use Test::More;
    use Person;
    use Car;
    use Pet;
    use PersonProcessorImpl;

    sub setup :Test(setup) {
    my $self = shift;
    $self->{processor} = PersonProcessorImpl->new();
    }

    sub should_return_false_for_jones :Test {
    my $person = Person->new(last_name => 'Jones');
    ok(!$self->{processor}->process($person));
    }

    sub should_return_true_for_one_car :Test {
    my $person = Person->new(cars => [Car->new]);
    ok($self->{processor}->process($person);
    }

    sub should_return_false_for_one_car_and_more_than_one_pet :Test {
    my $person = Person->new(
    cars => [Car->new],
    pets => [Pet->new, Pet->new],
    );
    ok($self->{processor}->process($person);
    }

    Without a a need for any builder class. Named arguments (and the ability for a class to have defaults for fields) as a language feature just removes almost all the reasons for a Builder pattern.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.