The Builder

Glarimy Technology Services
3 min readJul 30, 2021
The Rippon Building, Chennai (Credit: Amol Sriram Koyya)

Design Patterns are tough nuts to crack, especially for the green-horns. Yet, they continue to play a critical role in building reusable object-oriented systems, ever since they were published by the famous Gang of Four, almost three decades ago.

Let us understand the Builder, one of the six GoF creational patterns, in the context of a Java Web server.

The interaction between the clients and the server can be summed up in three steps:

Step 1: The client makes a request to the server over HTTP protocol and waits for the response.
Step 2: The server processes the request and sends back the response.
Step 3: The client receives the response.

Our focus is on the response object.

According to the protocol, both the requests and responses carry headers and optional payloads. Each of the headers is just a simple key-value pair. Since HTTP is a text-based protocol, both the keys and the values are in the text format. And apart from the well-known HTTP headers, a server application developer can also choose to send some custom headers as well, while responding to a request.

As different responses carry different sets of headers, it is impractical to override the constructor for every combination. Also, in many cases, the response might have to be built incrementally, one step at a time, since the server application might not have the information for all headers, all at once.

The scenario is analogous to that of making an order at a restaurant that offers several combinations. Typically, a waiter helps the customer in building the order, interactively. The waiter waits till the customer confirms the order, before notifying the kitchen for actual preparation. In other words, the restaurant delays allocation of the resources like the chef, burner, ingredients, etc., till the order is confirmed. This delay saves the wastage, as it is also possible that the customer may not even place the order in the end!

The builder pattern also recommends a similar setup.

package com.glarimy.builder;

import java.net.InetAddress;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.management.ImmutableDescriptor;

public class Response {
private String payload;
private Map<String, String> headers;

private Response(Map<String, String> headers, String payload) {
this.headers = headers;
this.payload = payload;

if (headers.get("status") == null)
headers.put("status", Integer.toString(200));

if (headers.get("type") == null)
headers.put("type", "plain/text");

headers.put("length", Integer.toString(payload.length()));
headers.put("timestamp",
Long.toString(new Date().getTime()));

try {
headers.put("address",
InetAddress.getLocalHost().getHostName());
} catch (Exception e) {
headers.put("address", "not available");
}
}

public int getStatus() {
return Integer.parseInt(headers.get("status"));
}

public String getType() {
return headers.get("type");
}

public String getPayload() {
return payload;
}

public Map<String, String> getHeaders() {
return Collections.unmodifiableMap(headers);
}

public int getLength() {
return Integer.parseInt(headers.get("length"));
}

public Date getTimestamp() {
return new Date(Long.parseLong(headers.get("timestamp")));
}

public String getAddress() {
return headers.get("address");
}

public static class ResponseBuilder {
private Map<String, String> headers
= new HashMap<String, String>();

public ResponseBuilder setStatus(int status) {
headers.put("status", Integer.toString(status));
return this;
}

public ResponseBuilder setType(String type) {
headers.put("type", type);
return this;
}

public ResponseBuilder setLocation(String location) {
headers.put("location", location);
return this;
}

public ResponseBuilder addHeader(String key, String value) {
headers.put(key, value);
return this;
}

public Response build(String payload) {
return new Response(headers, payload);
}

}

}

The ResponseBuilder is playing the role of a waiter in the restaurant. It is offering several optional utility methods like setStatus() to make the job easier. However, it delays the creation of the actual Response object till the build() method is called. This is a good idea because the creation of the Response object is a bit resource intensive as it needs to compute some important headers.

That sums up the builder pattern. Here is the possible usage:

Response response = new Response.ResponseBuilder()
.setStatus(201)
.setLocation("http://www.glarimy.com/blog/1")
.build("your entity");

The wizards that we use to make orders on an e-commerce portal, or to install a piece of software, or to build social media profile, are all builders!

Use this pattern to offer the developers an interactive way to create a resource-intensive object that has plenty of optional properties.

--

--

Glarimy Technology Services

Krishna Mohan Koyya, Principal Consultant, Glarimy Technology Services, Bengaluru, India