alexcuesta

My tech blog

Archive for October 2012

The builder pattern

leave a comment »

One thing I really miss in Java language is more readability when it comes to create an object. As you know, the natural way of creating an object in Java is by using its constructor:

Book book = new Book("Clean Code");

This is pretty readable because it contains only one parameter. However, what happens when the object expects more than one parameter to be correctly initializated?

Item table = new Item(2, "Wooden table", 2, 3, 0.5);

The problem with this constructor is that we don’t know what those numbers actually mean.

I love the way Groovy solves this problem:

Item table = new Item(id:2, name:"Wooden table", width:2, length:3, height:0.5);

Do we have any acceptable solution in Java? Yes, we have the Builder Pattern:

Example of client code:

Item item = new Item.Builder()
                    .withId(2)
                    .withName("Wooden table")
                    .withWidth(2)
                    .withLength(3)
                    .withHeight(0.5).build();

This pattern has been traditionally used in tests but I also like to use it as a Factory class. It is not ideal but at least I know what each value mean when I read the code. Anyway, the problems I find about this pattern are:

  • More code to write.
  • More maintaining is needed when the class changes (adding or removing a property for example)
  • It adds extra boilerplate code such as the “build()” method.
  • The object could be created omitting the minimum number of parameters to assure the correct initialization. In this case, it’s a good idea to throw an exception if the method “build()” is called and any of the essential attributes are omitted.

Example of builder code:

public class Item {

	private Integer id;
	private String name;
	private Float width;
	private Float length;
	private Float height;
	
	private Item() {}

	public Integer getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public Float getWidth() {
		return width;
	}

	public Float getLength() {
		return length;
	}

	public Float getHeight() {
		return height;
	}

	public static class Builder {
		
		private Item item;
		
		public Builder() {
			this.item = new Item();
		}

		public Builder withId(int id) {
			this.item.id = id;
			return this;
		}
		
		
		public Builder withName(String name) {
			this.item.name = name;
			return this;
		}
	
		public Builder withWidth(float width) {
			this.item.width = width;
			return this;
		}
		
		public Builder withLength(float length) {
			this.item.length = length;
			return this;
		}

		public Builder withHeight(float height) {
			this.item.height = height;
			return this;
		}

		public Item build() {
			validate();
			return this.item;
		}
		
		private void validate() {
			if (item.id == null || StringUtils.isBlank(item.name))
				throw new IllegalStateException();
		}

	}
}

And a couple of unit tests that shows the item builder behaviour:

	@Test
	public void shouldBuildWithAllInfo() throws Exception {
		Item item = new Item.Builder()
				    .withId(1)
				    .withName("item")
				    .withWidth(2.0f)
				    .withLength(3.0f)
				    .withHeight(0.5f)
				    .build();
		
		assertThat(item.getId(), is(1));
		assertThat(item.getName(), is("item"));
		assertThat(item.getWidth(), is(2.0f));
		assertThat(item.getLength(), is(3.0f));
		assertThat(item.getHeight(), is(0.5f));
	}
	
	@Test(expected=IllegalStateException.class)
	public void shouldNotBuildWithoutMinimalInfo() throws Exception {
		Item item = new Item.Builder().build();
	}

Written by alexcuesta

October 26, 2012 at 1:27 am

Posted in Java