Builder pattern in Java

Glendon 167 Published: 07/27/2024

Builder pattern in Java

Builder pattern is a creational design pattern that separates the construction of an object from its representation. This allows for more flexibility and control over how objects are created.

In Java, the builder pattern can be implemented using a class hierarchy where one class acts as a director or builder, and another class acts as a product or target being built.

Let's consider a simple example of building a house. We have a House class that represents the final product, and a HouseBuilder class that is responsible for constructing it.

// Product class - House

public class House {

private String roof;

private String walls;

private String doors;

public House(String roof, String walls, String doors) {

this.roof = roof;

this.walls = walls;

this.doors = doors;

}

public void display() {

System.out.println("House details: Roof - " + roof +

", Walls - " + walls + ", Doors - " + doors);

}

}

// Builder class - HouseBuilder

public class HouseBuilder {

private String roof;

private String walls;

private String doors;

public House build() {

return new House(roof, walls, doors);

}

public HouseBuilder setRoof(String roof) {

this.roof = roof;

return this;

}

public HouseBuilder setWalls(String walls) {

this.walls = walls;

return this;

}

public HouseBuilder setDoors(String doors) {

this.doors = doors;

return this;

}

}

// Director class - HouseDirector

public class HouseDirector {

private HouseBuilder builder;

public HouseDirector(HouseBuilder builder) {

this.builder = builder;

}

public House construct() {

return builder.build();

}

}

In the above example, House is the product being built, and HouseBuilder is the builder that constructs it. The HouseDirector class serves as a director that orchestrates the construction of the house.

The benefits of using the builder pattern are:

It separates the construction of an object from its representation. It allows for more flexibility and control over how objects are created. It reduces the need for constructors with many parameters. It provides a way to construct complex objects step-by-step, rather than all at once.

To use the builder pattern in Java, you would create an instance of the HouseBuilder class, set the various properties using the setter methods, and then call the build() method to get the final House object. This can be done through a director class as shown above.

Here's how you might use it:

public class Main {

public static void main(String[] args) {

HouseDirector houseDirector = new HouseDirector(new HouseBuilder());

House house = houseDirector.construct();

house.display();

}

}

In the main() method, we create an instance of HouseDirector and set the properties using the setter methods on the HouseBuilder. Finally, we call the construct() method to get the final House object, which we then display.

Overall, the builder pattern is a powerful design pattern that can simplify the construction of complex objects in Java.

java builder vs constructor

The age-old debate! In the world of object-oriented programming (OOP), both constructors and builders are used to create objects, but they serve different purposes and have unique characteristics.

Constructors

A constructor is a special method in a class that initializes objects when they're created. It's called automatically when an instance of the class is instantiated. The primary goal of a constructor is to set the initial state of the object by assigning values to its attributes (fields or properties). Constructors don't return any value, not even void. When you create an object using the new keyword, the constructor is invoked.

Here are some key characteristics of constructors:

They're called automatically when an instance is created. They don't return any value. Their main purpose is to initialize objects by setting attribute values. They can take arguments (parameters) to customize the initialization process.

Builders

A builder, on the other hand, is a design pattern that allows for flexible and fluent object creation. Builders are often used in situations where the construction of an object involves multiple steps or has many optional parameters. The idea behind a builder is to separate the creation of an object from its representation, making it easier to create objects in complex scenarios.

Here are some key characteristics of builders:

They're not part of the class definition. Builders are typically static methods (not instance methods) that return a new instance of the class. Builders allow for step-by-step construction of an object, which is particularly useful when there are many optional parameters or when the creation process involves multiple steps.

Key differences

Now that we've covered the basics of constructors and builders, let's highlight their key differences:

Purpose: Constructors initialize objects by setting attribute values, while builders facilitate flexible and fluent object creation. Scope: Constructors are part of the class definition, whereas builders are separate methods (usually static) that create instances of the class. Return type: Constructors don't return any value, while builders typically return a new instance of the class.

When to use each

So, when should you use constructors and when should you use builders?

Use constructors when: You need to initialize objects with default or minimal setup. The construction process is simple and doesn't require many steps. You want to ensure that objects are created correctly without allowing for manual modification of their state (e.g., using setters). Use builders when: You have a complex object creation process with multiple steps or optional parameters. You need to provide more flexibility in creating objects, such as allowing for step-by-step construction. You want to decouple the representation of an object from its creation process.

In summary, constructors are great for simple object initialization, while builders excel at facilitating flexible and fluent object creation. Both have their places in the world of OOP, and understanding when to use each is crucial for effective software development.