Builder pattern + inheritance

In general, it is very simple to implement in Java the builder pattern, a few lines of code and the problem is solved but, when we are using inheritance, it is not as intuitive apparently as it should be. I have lately seen poor attempts of doing it and not achieving the desired result.

In this article, we are going to build a very simple example of that.

public class Parent {

    private final String a;

    protected Parent(final Builder<?> builder) {
        this.a = builder.a;
    }

    public String getA() { return a; }

    public static class Builder<T extends Builder<T>> {

        private String a;

        public T a(final String a) {
            this.a = a;
            return (T) this;
        }

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

In this first class, the parent class, we can see we are using generics to allow child classes to pass their builders.

public class Children extends Parent {

    private final String b;

    protected Children(final Builder builder) {
        super(builder);
        this.b = builder.b;
    }

    public String getB() {
        return b;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder extends Parent.Builder<Builder> {
        private String b;

        public Builder b(final String b) {
            this.b = b;
            return this;
        }

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

Here, we can see how we pass the child builder in the diamond operator, this will allow us to add values for the properties to the patent and to the child using the builder.

public class Main {

    public static void main(String[] args) {
        final Children children = Children.builder()
            .a("Hi")
            .b("Bye")
            .build();

        System.out.println(children.toString());
    }
}

Here, we can see how to use the builder. Thanks to the generics, the call to .a(“Hi”) returns a child builder and not a parent builder what it would make impossible to call .b(“Bye”).

I hope it is useful.

Builder pattern + inheritance

Design Patterns: Builder

This is a creational pattern, as it is used to control class instantiation. The builder pattern is a design pattern that allows for the step-by-step creation of complex objects using the correct sequence of actions. The construction is controlled by a director object that only needs to know the type of object it is to create.

Elements involved:

  • Product: The product class defines the type of the complex object that is to be generated by the builder pattern.
  • Builder: This abstract base class defines all of the steps that must be taken in order to correctly create a product. Each step is generally abstract as the actual functionality of the builder is carried out in the concrete subclasses. The getProduct method is used to return the final product. The builder class is often replaced with a simple interface.
  • ConcreteBuilder: There may be any number of concrete builder classes inheriting from Builder. These classes contain the functionality to create a particular complex product.
  • Director: The director class controls the algorithm that generates the final product object. A director object is instantiated and its construct method is called. The method includes a parameter to capture the specific concrete builder object that is to be used to generate the product. The director then calls methods of the concrete builder in the correct order to generate the product object. On completion of the process, the getProduct method of the builder object can be used to return the product.

We should use the Builder design pattern when:

When object creation algorithms should be decoupled from the system, and multiple representations of creation algorithms are required. This decoupling is useful as you can add new creation functionality to your system without affecting the core code. You also get control over the creation process at runtime with this approach.

Let´s see some code:

public abstract class Builder {
    public abstract void buildA();
    public abstract void buildB();
    public abstract void buildC();
    public abstract Product getProduct();
}
public class ConcreteBuilder extends Builder {
    private final Product product = new Product();
    @Override
    public void buildA() { this.product.setA("A"); }
    @Override
    public void buildB() { this.product.setB("B"); }
    @Override
    public void buildC() { this.product.setC("C"); }
    @Override
    public Product getProduct() { return this.product; }
}
public class Product {
    public String a;
    public String b;
    public String c;
    public String getA() { return a; }
    public void setA(String a) { this.a = a; }
    public String getB() { return b; }
    public void setB(String b) { this.b = b; }
    public String getC() { return c; }
    public void setC(String c) { this.c = c; }
}
public class Director {
    public Product construct(final Builder builder) {
        builder.buildA();
        builder.buildB();
        builder.buildC();
        return builder.getProduct();
    }
}
public class Main {
    public static void main(String[] args) {
        final Director director = new Director();
        final Product product = director.construct(new ConcreteBuilder());
        System.out.println(String.format("Product: A = %s, B = %s, C = %s", product.getA(), product.getB(), product.getC()));
    }
}

You can find the code in my GitHub repository “design-apperns“.

Not exactly matching the pattern described in the book wrote by the GoF, we can see a couple more definitions/implementations of the Builder pattern.

The first one is used to build immutable objects and, in addition, it makes easier to add new properties to your object without having a constructor with a huge number of parameters. It is similar to a fluent interface usually implemented by using method cascading or method chaining.

Let´s see an example.

public class Product {
    private final String a;
    private final String b;
    private final String c;
    private final String d;
    private final String e;
    private Product(ProductBuilder productBuilder) {
        this.a = productBuilder.a;
        this.b = productBuilder.b;
        this.c = productBuilder.c;
        this.d = productBuilder.d;
        this.e = productBuilder.e;
    }
    public String getA() { return a; }
    public String getB() { return b; }
    public String getC() { return c; }
    public String getD() { return d; }
    public String getE() { return e; }
    @Override
    public String toString() {
        return "Product{" + "a=" + a + ", b=" + b + ", c=" + c + ", d=" + d + ", e=" + e + '}';
    }
    public static class ProductBuilder {
        private final String a;
        private final String b;
        private String c; // Optional
        private String d; // Optional
        private String e; // Optional
        public ProductBuilder(String a, String b) {
            this.a = a;
            this.b = b;
        }
        public ProductBuilder setC(final String c) {
            this.c = c;
            return this;
        }
        public ProductBuilder setD(final String d) {
            this.d = d;
            return this;
        }
        public ProductBuilder setE(final String e) {
            this.e = e;
            return this;
        }
        public Product build() {
            return new Product(this);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.print(new Product.ProductBuilder("A", "B")
                .setC("C")
                .setD("D")
                .setE("E")
                .build()
                .toString());
    }
}

You can find the example in the repository, in the builder project in the package labeled as “variant1”.

The second example, it is basically the same, but applied to POJOs to make easier to build them. It is a much more simplified version of the previous example.

Let´s see how this is:

public class Product {
    private String a;
    private String b;
    public String getA() { return this.a; }
    public Product setA(final String a) {
        this.a = a;
        return this;
    }
    public String getB() { return this.b; }
    public Product setB(final String b) {
        this.b = b;
        return this;
    }
    @Override
    public String toString() {
        return "Product{" + "a=" + a + ", b=" + b + '}';
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println(new Product()
                .setA("A")
                .setB("B")
                .toString());
    }
}

You can find the example in the repository, in the builder project in the package labeled as “variant2”.

Design Patterns: Builder