Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

The Builder Design Pattern for Big Classes

DZone's Guide to

The Builder Design Pattern for Big Classes

Who doesn't love the classic Builder Pattern? But what happens when your classes use too many arguments? Let's take a shot at a more streamlined approach.

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

As per the original definition of Builder Design Pattern, it separates the construction of a complex object from its representation so that the same construction process can create different representations. One side effect of this pattern is that we can avoid mistakes associated with the construction of an object with a constructor that takes too many arguments. For example, consider the following class:

public class Employee {
      private int id;
      private String name;
      private String department;
      private String address;
      private String phone;
      private String mobile;

      public Employee(String name, String deptt, String address,
                  String phone, String mobile) {
            super();
            this.id = generateId();
            this.name = name;
            this.deptt = deptt;
            this.address = address;
            this.phone = phone;
            this.mobile = mobile;
      }

      private int generateId(){
            int id = 0; //Generate a unique id here with some mechanism
            return id;
      }
}


You see the problem here. The constructor asks the developer to send the arguments in a specific order. To double the problem, all the arguments are Strings and anybody using this constructor needs to remember the order or check the documentation, if there is any present. Imagine a situation when there are more than 10 arguments. This is very cumbersome in that case.

How do we make life easier for developers who are using this class? One way could be providing a default constructor and setter methods for each of the attributes. I see a number of issues with this approach, namely:

  • What if my class should not have a default constructor, i.e. we cannot imagine an Employee having no name, department, address, phone, or mobile. One argument could be that we have a constructor with mandatory attributes. But then, if the list of mandatory attributes itself is too long, then we again end up with the problem that we want to solve. However, if the mandatory arguments are not too large in number, then we may use this approach.
  • If we are using setters, there are times when we have the Employee object created but not complete in a logical sense, i.e. we are still setting up the properties. This inconsistent state of the object may cause issues when there are multiple threads trying to access the object.

The better approach would be to use the Builder Design pattern as given in the code down below.

Before we see it, however, there are a couple of points to be noted in the implementation.

  • The constructor for the Employee class is private. This ensures that no one can create an instance using the problematic constructor. This pre-empts the urge by developers to use the constructor directly to create an instance.
  • Builder is an inner class of Employee. We need to do this, as there are no public setter methods in Employee for the reason described above, and Builder needs to have access to the private properties of Employee.
public class Employee {
    private int id;
    private String name;
    private String department;
    private String address;
    private String phone;
    private String mobile;

    private Employee(String name, String deptt, String address,
        String phone, String mobile) {
        super();
        this.id = generateId();
        this.name = name;
        this.department = deptt;
        this.address = address;
        this.phone = phone;
        this.mobile = mobile;
    }

    private int generateId() {
        //Generate an id with some mechanism
        int id = 0;
        return id;
    }

    @Override
    public String toString() {
        return "Employee [id=" + id + ", name=" + name + ", department=" +
            department + ", address=" + address + ", phone=" + phone + ", mobile=" + mobile + "]";

    }

    static public class Builder {
        private int id;
        private String name;
        private String department;
        private String address;
        private String phone;
        private String mobile;
        public Builder() {}

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

        public Builder department(String deptt) {
            this.department = deptt;
            return this;
        }

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

        public Employee build() {
            Employee emp = new Employee(name, department, address, phone, mobile);
            return emp;
        }
    }
}



The following code shows how we use this to create an instance of the Employee class:

public class TestMain {
    public static void main(String[] args) {
        Employee.Builder builder = new Employee.Builder();
        Employee emp = builder.address("my address").department("my deptt").name("my name").build();
        System.out.println("Employee created is " + emp);
    }
}


Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
java ,design patterns ,builder pattern ,arguments ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}