Home Design Pattern - Builder
Post
Cancel

Design Pattern - Builder

What is Builder Design Pattern?

Design patterns represent the best practice when you code in object-oriented programming. There are multiple design patterns. In this blog, we focus on one of them: Builder Design Pattern

Have you come across the situation where you want to initiate a complext object with many parameters, some of which are optional? It is difficult to initiate it as you need to define multiple constructors. The solution is doable but not beautiful. This is where Builder design pattern can help. Builder can construct a complicated object step by step.

How does Builder Design Pattern work?

In java, there is an easy way to implement Builder design pattern by Lombok. You can annotate a class with @Builder. For example,

1
2
3
4
5
6
7
8
9
10
11
@AllArgsConstructor
public class Employee {
    String name;
}

@Builder
public class Company {
    String name;
    String location;
    Employee[] employees;
}

The Company class uses Builder pattern. When you create an object, instead of using new, you can use following code:

1
2
3
4
Company company = Company.builder()
                         .name("Grey")
                         .location("Seattle")
                         .build();

builder() creates a builder inner object and you can use clear way to set each parameter. If some optional parameters are not needed, you can simply skip them. build() creates the object.

You might wonder how @Builder does the magic. If we reveal the underlying logic behind it, we can rewrite it in Vanilla Java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class Company {
    String name;
    String location;
    Employee[] employees;

    public Company(String name, String location, Employee[] employees) {
        this.name = name;
        this.location = location;
        this.employees = employees;
    }

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

    public static class CompanyBuilder {
        String name;
        String location;
        Employee[] employees;

        CompanyBuilder() {}

        public CompanyBuilder name(String name) {
            this.name = name;
            return this;
        }

        public CompanyBuilder location(String location) {
            this.location = location;
            return this;
        }

        public CompanyBuilder employees(Employee[] employees) {
            this.employees = employees;
            return this;
        }

        public Company build() {
            return new Company(name, location, employees);
        }
    }
}

You have understood the classic usage of Builder pattern. However, some situations happen where class fields are different from the input you would like to pass. In the example above, if we want to configure employees field during object construction, @Builder can only allow you use exact same type as this field. That means, you need to pass in a list of Employee objects. But you might not want to pass Employee objects directly. Instead, you pass in a list of employee names and construct employee objects during company object initiation. Then @Builder annotated on class is not enough as you need custom build functions. Here comes the second way to use Builder. You can also annotate on a function. Let’s cut into implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@AllArgsConstructor
public class Company {
    String name;
    String location;
    List<Employee> employees;

    @Builder
    public static Company build(String name, String location, List<String> employeeNames) {
        List<Employee> employees = employeeNames
          .stream()
          .map(employeeName -> new Employee(employeeName))
          .collect(Collectors.toList());
        return new Company(name, location, employees);
    }
}

This allows writing custom build logic and suits our need. You can also implement in vanilla java.

This post is licensed under CC BY 4.0 by the author.

Git 101

Why Cloud?

Comments powered by Disqus.