Builder -> Creational Arrogant Design Pattern

Arrogant Design Patterns ( by Hafiz Waleed Hussain )

Hi, I hope everyone is doing good.

Today, we are going to discuss Builder Design Pattern, a pretty simple but amazing Design Pattern.

In case you missed the Introductory Post of Arrogant Design Patterns.
More Posts on Design Patterns https://www.uwanttolearn.com/design-patterns/

Revision:

We need to do some concepts revise, which are essential from the perspective of Builder Design Patterns.

Note: I am going to use Java for this post. In the case of Kotlin, in most cases, there is no need to use the Builder Pattern because we can give default parameter values.

I am sure everyone who is reading this blog is aware of how to use

  • Classes, Objects
  • Constructor Parameters
  • Constructor
  • Overload Constructors
  • Mandatory Vs Optional

How to create an Object:

public class NameOfAClass{}
NameOfAClass object = new NameOfAClass()    

In the above code, first I created a class with the name “NameOfAClass” and after that, I created an object from this class.

Constructor Parameters:

public class NameOfAClass{
    private String s;
    public NameOfAClass(String s){
        this.s = s;
    }
}

In the above code, we have a NameOfAClass(String s). Here ‘s’ is a Constructor Parameter.

Overload Constructors:

public class NameOfAClass{
    private String s;
    private Integer i;
    private Float f;

    public NameOfAClass(String s) {
        this(s,null);
    }

    public NameOfAClass(String s, Integer i) {
        this(s,i, null);
    }

    public NameOfAClass(String s, Integer i, Float f) {
        this.s = s;
        this.i = i;
        this.f = f;
    }
}

In the above code, we can see multiple constructors; this is called Constructor Overloading. One important point, how I implemented this Constructor Overloading that is called Constructor Chaining. Like in this example, One argument constructor is calling the two-argument constructor with null as a second parameter, then in the two-argument constructor, we are calling the three-argument constructor with the third parameter value is null. It is called Constructor Chaining.

Mandatory Vs Optional:

In coding, we have two types of fields or parameters; one is called Mandatory, and the other is called Optional. Now, I am going to use this concept from the perspective of Constructor Parameters.

public class NameOfAClass{
private String id;

public NameOfAClass(String id) {
this.id = id;
}
}

In the above code, you can imagine that it is some entity that I want to save in the Database. So here id is a mandatory field.

Additional Sharing: From the perspective of proper class design, I always prefer to check mandatory fields at the time of a Construction of the object, especially in the case of Java, because a client can give a null value. To make our code perfect, we should add the checks against mandatory fields. Now, I am going to change the above code as per good class design practices.

public class NameOfAClass{
    private String id;

    public NameOfAClass(String id) {
        if(id == null)
            throw new IllegalArgumentException("id is a Mandatory field");
        this.id = id;
    }
}

public static void main(String[] args) {
    NameOfAClass object = new NameOfAClass(null); // Exception
}

In the above code, now the client is not able to give null as a Parameter. So always remember, if you have a mandatory field or parameter, then always check its value at the construction time. For example, we can improve more on our above class code. For example, as per our business requirement, id should not be null and not less than ten characters.

public class NameOfAClass{
    private String id;

    public NameOfAClass(String id) {
        if(id == null)
            throw new IllegalArgumentException("id is a Mandatory field");
        if(id.length() < 10)
            throw new IllegalArgumentException("id should be minimum 10 characters");
            
        this.id = id;
    }
}

public static void main(String[] args) {
    NameOfAClass object = new NameOfAClass("12345"); // Exception
}

Now, I am going to share with you one of my observations. On some code basis, we find out developers don’t care about the mandatory fields, and due to this, they mostly face issues + they are theoretically too good with Mandatory + Optional concepts. Still, practically they are afraid to throw the exception. So don’t be scared please throw the exception if in case the client is not giving you the proper value.

public class NameOfAClass{
    private String id; // Mandatory
    private String title; // Optional

    public NameOfAClass(String id, String title) {
        if(id == null)
            throw new IllegalArgumentException("id is a Mandatory field");
        if(id.length() < 10)
            throw new IllegalArgumentException("id should be minimum 10 characters");

        this.id = id;
        this.title = title;
    }
}

public static void main(String[] args) {
    NameOfAClass object = new NameOfAClass("thig-jhbf-875bfubfy7-48u5",null);
}

Now, in the above code, I have one more field with the name title. As per the business requirement title is optional, it’s mean the client can give me the null value, and I will accept that value. I hope the Mandatory and Optional concept is clear.
I am going to spend some more time improving our above code. So our client should enjoy it when he/she uses our API.

public class NameOfAClass{
    private String id; // Mandatory
    private String title; // Optional

    public NameOfAClass(String id) {
        this(id,null);
    }

    public NameOfAClass(String id, String title) {
        if(id == null)
            throw new IllegalArgumentException("id is a Mandatory field");
        if(id.length() < 10)
            throw new IllegalArgumentException("id should be minimum 10 characters");

        this.id = id;
        this.title = title;
    }
}

Now, in the above code, what I did? Only I added a one-argument constructor because I know id is a mandatory field, and the title is optional. So it’s time to see how our client will use this code.

public static void main(String[] args) {
    // Only give me the Mandatory field Id
    NameOfAClass object = new NameOfAClass("thig-jhbf-875bfubfy7-48u5");

    // Give me the Mandatory + Optional Field Value
    NameOfAClass object = new NameOfAClass("thig-jhbf-875bfubfy7-48u5", "Title");

    // Still if client want to send you null he can use this option
    NameOfAClass object = new NameOfAClass("thig-jhbf-875bfubfy7-48u5", null);
}

Wow, we have an excellent API, and I am sure our client will be happy to use our code. By the way, here the client maybe is your team member :). In the end, what we did, we used the Overloading Constructor and Constructor Chaining.

In the above code, We can see one more benefit of Constructor Chaining. For example, the business decided the minimum character should be 5 for the id field. So, in this case, only I need to change in one constructor, and all other overloaded constructors automatically obey the new change.

Builder Design Pattern:

There are different use cases where we can use the Builder Design Pattern and due to this reason, we will have more than one definition to observe in our code to find out where we can implement Builder Design Pattern.

I will start with the most basic use case. So our first cheat sheet definition of Builder Design Pattern is.

  • Mandatory Vs Optional

We need to find out the classes which have mandatory and optional Constructor Parameters. Now, every developer implements this scenario differently. For example, I am going to take one example, which will show you different approaches to implement constructors.

public class OtherObject{}

public class NameOfAClass{
private String id; // Mandatory
private String name; // Mandatory
private String title; // Optional
private OtherObject object; //Optional

public NameOfAClass(String id, String name, String title, OtherObject object) {
this.id = id;
this.name = name;
this.title = title;
this.object = object;
}
}

In the above code, we have four fields in a constructor, and we have only one constructor. We can see two fields are mandatory, and two fields are optional. As per our definition, this scenario is a good use case of the Builder Design Pattern.

The second approach to implement this same example with multiple constructors.

public class OtherObject{}

public class NameOfAClass{
private String id; // Mandatory
private String name; // Mandatory
private String title; // Optional
private OtherObject object; //Optional

public NameOfAClass(String id, String name) {
this(id, name, null,null);
}

public NameOfAClass(String id, String name, String title) {
this(id, name, title, null);
}

public NameOfAClass(String id, String name, String title, OtherObject object) {
this.id = id;
this.name = name;
this.title = title;
this.object = object;
}
}

In the above code, we have an overloaded constructor with constructor chaining. Anywhere you can see overloaded constructors with constructor chaining, in most cases, that is the right candidate for Builder Design Pattern because overloaded constructors mostly use to tackle the optional values in your code.

Note: In our case, we have only four constructor parameters, but for this example, I am going to implement the Builder Design Pattern on this. In your case, always ask a question to your self, is constructor overloading is better or Builder Design Pattern. If you have few fields, then try to go with Constructor Overloading, but if you feel your API is exploding due to a lot of Constructors, then refactor to Builder Design Pattern. There is no hard and fast rule. It depends on you and your team.

Basic Implementation of Builder Design Pattern:

First step:

Any API or class which we want to give as a Builder Design Pattern to our client. We need to restrict its instantiation from outside of the class. So for that, we will change its public constructor to private, as shown below:

public static class NameOfAClass {
    private String id; // Mandatory
    private String name; // Mandatory
    private String title; // Optional
    private OtherObject object; //Optional

    private NameOfAClass() {
        // Private Constructor
    }
}

Step two:

Create a builder class who is responsible for creating the object of our NameOfAClass object.

public static class NameOfAClass {
    private String id; // Mandatory
    private String name; // Mandatory
    private String title; // Optional
    private OtherObject object; //Optional

    private NameOfAClass() {
        // Private Constructor
    }

    public static class Builder {
    }
}

Step three:

We need the duplication of all the original class fields into the Builder class, as shown below:

public static class NameOfAClass {
    private String id; // Mandatory
    private String name; // Mandatory
    private String title; // Optional
    private OtherObject object; //Optional

    private NameOfAClass() {
        // Private Constructor
    }

    public static class Builder {
        private String id; 
        private String name; 
        private String title; 
        private OtherObject object;
    }
}

Step four:

Create a Builder constructor with mandatory fields, as shown below:

public static class NameOfAClass {
    private String id; // Mandatory
    private String name; // Mandatory
    private String title; // Optional
    private OtherObject object; //Optional

    private NameOfAClass() {
        // Private Constructor
    }

    public static class Builder {

        private String id;
        private String name;
        private String title;
        private OtherObject object;
        
        public Builder(String id, String name){
            this.id = id;
            this.name = name;
        }
    }
}

Step five:

Create the setter methods for Optional values in Builder class with one difference. We will return the Builder object reference from our setter methods, as shown below:

public static class NameOfAClass {
    private String id; // Mandatory
    private String name; // Mandatory
    private String title; // Optional
    private OtherObject object; //Optional

    private NameOfAClass() {
        // Private Constructor
    }

    public static class Builder {

        private String id;
        private String name;
        private String title;
        private OtherObject object;

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

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

        public Builder setObject(OtherObject object) {
            this.object = object;
            return this;
        }
    }
}

Step six:

Now, we need to create a build method that creates the instance of a NameOfAClass in Builder, as shown below:

public static class NameOfAClass {
private String id; // Mandatory
private String name; // Mandatory
private String title; // Optional
private OtherObject object; //Optional

private NameOfAClass() {
// Private Constructor
}

public static class Builder {

private String id;
private String name;
private String title;
private OtherObject object;

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

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

public Builder setObject(OtherObject object) {
this.object = object;
return this;
}

public NameOfAClass build(){
NameOfAClass obj = new NameOfAClass();
obj.id = id;
obj.name = name;
obj.title = title;
obj.object = object;
return obj;
}
}
}

Now the implementation of the Builder class is complete. Its time to check how our clients will use this class in their codebase.

public static void main(String[] args) {

// Client needs to provide us minimum mandatory value to create
// the instance of NameOfAClass
NameOfAClass first = new NameOfAClass.Builder("id","name")
.build();

// Client can provide us the only one optional value as shown below
NameOfAClass second = new NameOfAClass.Builder("id","name")
.setTitle("title")
.build();


// Client can provide us the only optional value as shown below
NameOfAClass third = new NameOfAClass.Builder("id","name")
.setObject(new OtherObject())
.build();

// Client can provide us the all optional value as shown below
NameOfAClass fourth = new NameOfAClass.Builder("id","name")
.setTitle("title")
.setObject(new OtherObject())
.build();
}

There is also one more benefit we can see. For example, in the above code, the client can provide us a title or object in any order. Still, in the case of Constructor Overloading, the client needs to follow the constructor parameter implementation.

Until now we achieved our Builder Pattern cheat sheet definition.

  • Mandatory Vs Optional

Second Builder Pattern Implementation:

It is a little bit tricky; mostly, when you want to implement this approach, you need to think for a whole module and not at the class level. First, we will discuss this more, and later I will share with you the cheat sheet definition.

Also, here I am not able to go with a generic example, so please don’t focus on my example class names. Instead, try to grab the concept so you can use Builder Design Pattern in these types of use cases when they occur in your business requirements.

These days, we have a boom in e-commerce. We have a lot of websites or apps. Mostly when we do online or maybe grocery shopping, what is our process.

Step 1: We start selecting items
Step 2: Selected Items move into the cart
Step 3: Review the final Order in Cart
Step 4: Process Payment fo my Order

Now, In this whole process, I can see a use case of the Builder Design Pattern. But this time we don’t have Mandatory Vs. Optional Fields. Instead, I can see I have OrderBuilder (Cart) in which I will add the Items and once I will complete. I will click the payment process button, and at that time, OrderBuilder will build the Order object. This Order object I will pass to the Payment processing module.

In simple words, we can say, in any use case where we are selecting items, and then, in the end, we will build the order based on selected items. That is a good use case of the Builder Design Pattern.

Now, if you do observation around you, you can see these examples in the real-world. Also, you can find out this scenario in your daily coding tasks. For instance, A Coffee Cafe, you always select your items, and in the end, they will build your order. In fast-food chains, now they have a kiosk where you can choose the ala carte + combo meals, and in the end, you will complete your order by giving payment.

I hope the use case is clear, and Now, I am going to select an example of a Kiosk in a fast-food cafe.

Note: I am only focusing on the Builder Design Pattern, but if we do the proper system design, in that case, we have a lot of opportunities to use other Design Patterns with Builder Design Pattern. Like I can use Decorator Pattern when I want a Cheesy Fench Fries, or when I want to upgrade my Combo Meals. So in all these cases, I can use the Decorator Design Pattern. But for now, I do only focus on the Builder Design Pattern, and we will discuss Decorator and other Design Patterns in their posts.

Implementation:

As per our discussion in any use case, we can use an Item as a starting point. So I am going to create Item Interface.

interface Item {
    String name();
    Double price();
}

I created the Item interface is pretty basic, so that we can focus on the Builder Design Pattern.

Next, we need to create Items. I am going to choose some items from the real Kiosk which I used some days ago.

BigMacBurger, ChickenBurger
CoffeeLatte, CoffeeCappuccino
IceCreamVanilla
FrenchFriesMedium, FrenchFriesLarge
DrinkCocaCola DrinkSprite

Note: Here, we can create Abstract classes for the proper grouping, but for now, I am going to consider everything as an Item.

class BigMacBurger implements Item {
    @Override public String name() { return "BigMac"; }
    @Override public Double price() { return 4.0; }
}

class ChickenBurger implements Item{
    @Override public String name() { return "Chicken Burger"; }
    @Override public Double price() { return 3.0; }
}

class CoffeeLatte implements Item{
    @Override public String name() { return "Latte"; }
    @Override public Double price() { return 1.2; }
}

class CoffeeCappuccino implements Item{
    @Override public String name() { return "Cappuccino"; }
    @Override public Double price() { return 1.5; }
}


class IceCreamVanilla implements Item{
    @Override public String name() { return "Vanilla"; }
    @Override public Double price() { return 1.2; }
}

class FrenchFriesMedium implements Item{
    @Override public String name() { return "Medium French Fries"; }
    @Override public Double price() { return .8; }
}

class FrenchFriesLarge implements Item{
    @Override public String name() { return "Large French Fries"; }
    @Override public Double price() { return 1.0; }
}

class DrinkCocaCola implements Item{
    @Override public String name() { return "Coca cola"; }
    @Override public Double price() { return .4; }
}

class DrinkSprite implements Item{
    @Override public String name() { return "Sprite"; }
    @Override public Double price() { return .4; }
}

So we have an elementary Item class, only one thing I want to share with you. In the above code, we have FrenchFriesMedium and FriencFriesLarge. In my opinion, FrenceFries will be an Item, and Medium, Large should be decorations in proper system design (Use case of Decorator Design Pattern).

What’s next?

Now, we need to create an Order class and Order Builder class, and here we will use the same approach, which we used in Mandatory VS Optional use case with some small differences.

class Order{
    private List<Item> items;
    private String promo;

    private Order(){
        // Private Constructor
    }
}

Order class is pretty simple, now we will add the OrderBuilder class.

class Order{

    private List<Item> items;
    private String promo;
    
    private Order(){
        // Private Constructor
    }
    
    public static class OrderBuilder{

        private List<Item> items = new ArrayList<>();
        private String promo;

        public void addItem(Item item){
            items.add(item);
        }

        public void removeItem(Item item){
            items.remove(item);
        }

        public void applyPromo(String promo){
            this.promo = promo;
        }
        
        public Order build(){
            Order order = new Order();
            order.items = items;
            order.promo = promo;
            return order;
        }
    }
}

Again pretty simple code in OrderBuilder class, by the way, you can replace addItem name with add alaCarte.

Now, its time to see how our client will use this API.

public static void main(String[] args) {
OrderBuilder builder = new OrderBuilder();
builder.addItem(new BigMacCombo());
builder.addItem(new ChickenBurger());
builder.addItem(new CoffeeCappuccino());
builder.addItem(new FrenchFriesLarge());
builder.applyPromo("10Dollar");
Order order = builder.build();

// Some Payment Processor(order)
}

Looks fine, but I think we can improve the API.

class Order{

    private List<Item> items;
    private String promo;

    private Order(){
        // Private Constructor
    }

    public static class OrderBuilder{

        private List<Item> items = new ArrayList<>();
        private String promo;

        public OrderBuilder addItem(Item item){
            items.add(item);
            return this; // Imrpove change is this
        }

        public OrderBuilder removeItem(Item item){
            items.remove(item);
            return this; // Imrpove change is this
        }

        public OrderBuilder applyPromo(String promo){
            this.promo = promo;
            return this; // Imrpove change is this
        }

        public Order build(){
            Order order = new Order();
            order.items = items;
            order.promo = promo;
            return order;
        }
    }
}
public static void main(String[] args) {
    Order order = new OrderBuilder()
            .addItem(new BigMacCombo())
            .addItem(new ChickenBurger())
            .addItem(new CoffeeCappuccino())
            .addItem(new FrenchFriesLarge())
            .applyPromo("10Dollar")
            .build();

    // Some Payment Processor(order)
}

Looks nice. I think we can get more benefits from this approach. As we know, these chains don’t only have these ala cartes. Instead, they have Combo meal options, so its times to see how in this Builder Design Pattern, we can adjust that.

As I promise with you guys, I will only do focus on the Builder Design Pattern with Item interface. But to show you more power of this Pattern I am going to use an abstract class. Hopefully, everyone is aware of what is an abstract class and inheritance.

abstract class Combo implements Item {
protected List<Item> items = new ArrayList<>();
}

So in the above code, I created a pretty straight forward abstract class with the name Combo.

class BigMacCombo extends Combo {

    public BigMacCombo() {
        items.add(new BigMacCombo());
        items.add(new FrenchFriesMedium());
        items.add(new DrinkCocaCola());
    }

    @Override
    public String name() {
        return items.stream()
                .reduce("",
                        (names, item) -> names + " " + item.name(),
                        (s, s2) -> s + ", " + s2);
    }

    @Override
    public Double price() {
        return items.stream()
                .mapToDouble(value -> value.price()).sum();
    }
}

In the above code, I create one BigMacCombo class, a pretty simple class.

Now, its time to show the power of this approach. Now, we upgraded our SDK to 2.0.0, and now we will see how the client adds this BigMacCombo without breaking anything in their current code.

public static void main(String[] args) {
Order order = new OrderBuilder()
.addItem(new BigMacCombo()) // Big Mac Combo
.addItem(new CoffeeCappuccino())
.applyPromo("10Dollar")
.build();

// Some Payment Processor(order)
}

Wow, as you can see in the above code, how we can scale our application without breaking anything. Everything is pretty decoupled. I can add more Combos. I can introduce limited-time new deals by adding few lines of code. I think we already saw a lot of benefits from the Builder Design Pattern. So I am going directly to the conclusion :).

Conclusion:

In conclusion, I will repeat our cheat sheet Builder Design Pattern Definition.

  • Mandatory VS Optional
  • Any requirement in which we will select individual items and later we will check out those items in the form of an Order.
  • A requirement in which we will select individual items and later we will build or manufacture some object. Like Car Manufacturing, or Cooking.

More Posts on Design Patterns https://www.uwanttolearn.com/design-patterns/

Facebooktwitterredditpinterestlinkedinmailby feather

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.