Design patterns Builder Pattern Builder pattern in Java with composition


Example

Intent:

Separate the construction of a complex object from its representation so that the same construction process can create different representations

Builder pattern is useful when you have few mandatory attributes and many optional attributes to construct a object. To create an object with different mandatory and optional attributes, you have to provide complex constructor to create the object.Builder pattern provides simple step-by-step process to construct a complex object.

Real life use case:

Different users in FaceBook have different attributes, which consists of mandatory attribute like user name and optional attributes like UserBasicInfo and ContactInfo. Some users simply provide basic info. Some users provide detailed information including Contact info. In absence of Builder pattern, you have to provide a constructor with all mandatory and optional parameters. But Builder pattern simplifies the construction process by providing simple step-by-step process to construct the complex object.

Tips:

  1. Provide a static nested builder class.
  2. Provide constructor for Mandatory attributes of object.
  3. Provide setter and getter methods for optional attributes of object.
  4. Return the same Builder object after setting optional attributes.
  5. Provide build() method, which returns complex object

Code snippet:

import java.util.*;

class UserBasicInfo{
    String nickName;
    String birthDate;
    String gender;
    
    public UserBasicInfo(String name,String date,String gender){
        this.nickName = name;
        this.birthDate = date;
        this.gender = gender;        
    }
    
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("Name:DOB:Gender:").append(nickName).append(":").append(birthDate).append(":").
        append(gender);
        return sb.toString();
    }
}

class ContactInfo{
    String eMail;
    String mobileHome;
    String mobileWork;
    
    public ContactInfo(String mail, String homeNo, String mobileOff){
        this.eMail = mail;
        this.mobileHome = homeNo;
        this.mobileWork = mobileOff;
    }    
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("email:mobile(H):mobile(W):").append(eMail).append(":").append(mobileHome).append(":").append(mobileWork);
        return sb.toString();
    }
}
class FaceBookUser {
    String userName;
    UserBasicInfo userInfo;
    ContactInfo contactInfo;
    
    public FaceBookUser(String uName){
        this.userName = uName;
    }    
    public void setUserBasicInfo(UserBasicInfo info){
        this.userInfo = info;
    }
    public void setContactInfo(ContactInfo info){
        this.contactInfo = info;
    }    
    public String getUserName(){
        return userName;
    }
    public UserBasicInfo getUserBasicInfo(){
        return userInfo;
    }
    public ContactInfo getContactInfo(){
        return contactInfo;
    }
    
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("|User|").append(userName).append("|UserInfo|").append(userInfo).append("|ContactInfo|").append(contactInfo);
        return sb.toString();
    }
    
    static class FaceBookUserBuilder{
        FaceBookUser user;
        public FaceBookUserBuilder(String userName){
            this.user = new FaceBookUser(userName);
        }
        public FaceBookUserBuilder setUserBasicInfo(UserBasicInfo info){
            user.setUserBasicInfo(info);
            return this;
        }
        public FaceBookUserBuilder setContactInfo(ContactInfo info){
            user.setContactInfo(info);
            return this;
        }
        public FaceBookUser build(){
            return user;
        }
    }
}
public class BuilderPattern{
    public static void main(String args[]){
        FaceBookUser fbUser1 = new FaceBookUser.FaceBookUserBuilder("Ravindra").build(); // Mandatory parameters
        UserBasicInfo info = new UserBasicInfo("sunrise","25-May-1975","M");
        
        // Build User name + Optional Basic Info 
        FaceBookUser fbUser2 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
                                                setUserBasicInfo(info).build();
        
        // Build User name + Optional Basic Info + Optional Contact Info
        ContactInfo cInfo = new ContactInfo("xxx@xyz.com","1111111111","2222222222");
        FaceBookUser fbUser3 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
                                                setUserBasicInfo(info).
                                                setContactInfo(cInfo).build();
        
        System.out.println("Facebook user 1:"+fbUser1);
        System.out.println("Facebook user 2:"+fbUser2);
        System.out.println("Facebook user 3:"+fbUser3);
    }
}

output:

Facebook user 1:|User|Ravindra|UserInfo|null|ContactInfo|null
Facebook user 2:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|null
Facebook user 3:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|email:mobile(H):mobile(W):xxx@xyz.com:1111111111:2222222222

Explanation:

  1. FaceBookUser is a complex object with below attributes using composition:

    String userName;
    UserBasicInfo userInfo;
    ContactInfo contactInfo;
    
  2. FaceBookUserBuilder is a static builder class, which contains and builds FaceBookUser.

  3. userName is only Mandatory parameter to build FaceBookUser

  4. FaceBookUserBuilder builds FaceBookUser by setting optional parameters : UserBasicInfo and ContactInfo

  5. This example illustrates three different FaceBookUsers with different attributes, built from Builder.

    1. fbUser1 was built as FaceBookUser with userName attribute only
    2. fbUser2 was built as FaceBookUser with userName and UserBasicInfo
    3. fbUser3 was built as FaceBookUser with userName,UserBasicInfo and ContactInfo

In above example, composition has been used instead of duplicating all attributes of FaceBookUser in Builder class.

In creational patterns, we will first start with simple pattern like FactoryMethod and move towards more flexible and complex patterns like AbstractFactory and Builder.