Prototype Design Pattern

The Prototype pattern is a Creational Design Pattern that avoids costly creation of objects. The concept of this is to copy an existing object versus creating a new object all together. This is typically done using the clone() method from the Clonable interface. This design pattern is useful when creating objects becomes too costly or they take too much time.

Although you will be creating copies of an object, each instance will be unique. This is what’s called a Deep Copy. A deep copy will return a brand new object to a new instance, rather than a reference to the original object (Shallow Copy).  Shallow Copies are dangerous because you could change the parameters in one object and it would reflect in both the copied and original object. The construction of the objects will be handle by a Registry class.

We will implement a Device example of the Prototype pattern in Java. We will create an abstract class called Device that implements Clonable from the Java API. The DeviceRegistry  class will contain a static method that returns a cloned instance of Device.



1. Create an abstract class called Device. This will contain getters and setters for id and name. This will contain abstract methods powerOn() and addDevice() that will be overridden by sub-classes.

public abstract class Device implements Cloneable {
    private int id;
    private String deviceName;

    abstract void powerOn();
    abstract void addDevice();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDeviceName() {
        return deviceName;
    }

    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}


2. Add sub-classes Iphone and Pixel.

public abstract class Device implements Cloneable {
    private int id;
    private String deviceName;

    abstract void powerOn();
    abstract void addDevice();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDeviceName() {
        return deviceName;
    }

    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}
public class Pixel extends Device {
    @Override
    void powerOn() {
        System.out.println("Powered On Pixel");
    }

    @Override
    void addDevice() {
        System.out.println("Added Pixel Device");
    }
}


3. Create the Registry class that will contain a getDevice() method that will clone the Device object into a new instance.

package Prototype;

import java.util.HashMap;
import java.util.Map;

public class DeviceRegistry {

    private static Map<Integer, Device> devices = new HashMap();

    /**
     * Clones a Device object into a new instance by deviceId.
     *
     * @param deviceId - Id of device we want to clone.
     * @return
     */
    public static Device getDevice(Integer deviceId) {
        Device device = null;
        try {
            device = (Device) (devices.get(deviceId)).clone();
        } catch (CloneNotSupportedException ex) {

        }
        return device;
    }

    /**
     * Loads devices into objects. In a real application we would pull data from a database.
     */
    public static void loadDevices() {
        Iphone iphone = new Iphone();
        iphone.setId(1);
        iphone.setDeviceName("Iphone 8 Plus");
        devices.put(iphone.getId(), iphone);

        Pixel pixel = new Pixel();
        pixel.setId(2);
        pixel.setDeviceName("Google Pixel 4");
        devices.put(pixel.getId(), pixel);
    }
}

4. Create the client class. This will clone a Device instance into Iphone and Pixel.

public class ProtoypeClient {
    public static void main(String[] args) {
        DeviceRegistry.loadDevices();

        Device iphone = DeviceRegistry.getDevice(1);
        System.out.println(iphone);
        System.out.println(iphone.getDeviceName());
        iphone.addDevice();
        iphone.powerOn();
        System.out.println();

        Device pixel = DeviceRegistry.getDevice(2);
        System.out.println(pixel);
        System.out.println(pixel.getDeviceName());
        pixel.addDevice();
        pixel.powerOn();

    }
}
Prototype.Iphone@1b6d3586
Iphone 8 Plus
Added Iphone
Powered On Iphone

Prototype.Pixel@4554617c
Google Pixel 4
Added Pixel Device
Powered On Pixel

Process finished with exit code 0

Abstract Factory Design Pattern In Java

The Abstract Factory design pattern is a creational design pattern that contains a factory class which creates other factories. It is typically called the Factory of factories. There is an abstract Factory class that other factories inherit in order to implement their own factory method. 

A real world example of this would be a Database or Cache implementation. Let’s say you need to make database updates but need to update a SQL Server, MongoDB, and an Oracle database. These would use similar operations but would require a different implantation in order to connect, update, add and delete data from the database. Abstract Factory would come in handy here because you could have separate factories for a relational and non-relational database.

We are going to implement an example of the Abstract Factory Pattern with a Database implementation in Java. We will create an abstract class DatabaseFactory and 2 concrete classes RelationalDBFactory and NonRelationalDBFactory. The DatabaseFactory class will have a static method getFactory()that returns DatabaseFactory. The concrete classes will return a Database object depending on the type. 


1.  Create the abstract class DatabaseFactory. This contains a static method getFactory(String factory) that returns the correct factory object based on the parameter. getDatabase(String database) is an abstract method that the sub-classes will override.

public abstract class DatabaseFactory {

    /**
     * Returns the correct Factory object based on the type.
     * 
     * @param factory
     * @return
     */
    public static DatabaseFactory getFactory(String factory) {
        switch (factory) {
            case "Relational":
                return new RelationalDBFactory();
            case "NonRelational":
                return new NonRelationalDBFactory();
            default:
                return null;
        }
    }

    public abstract Database getDatabase(String database);
}

2. Create the sub-classes RelationalDBFactory and NonRelationalDBFactory. They contain their own version of getDatabase()  that will return a database object such as Mongodb, NoSQL, SQLServer, and MySQL.

public class NonRelationalDBFactory extends DatabaseFactory {

    /**
     * Returns a Database object of either Mongodb or NoSQL which are Non-relational databases.
     * @param database
     * @return
     */
    @Override
    public Database getDatabase(String database) {
        switch (database){
            case "Mongodb":
                return new MongoDB();
            case "NoSQL":
                return new NoSQL();
            default:
                return null;
        }
    }
}
public class RelationalDBFactory extends DatabaseFactory {

    /**
     *  Returns a Database object of either SQLServer or MySQL which are Relational databases.
     *
     * @param database
     * @return
     */
    @Override
    public Database getDatabase(String database) {
        switch (database){
            case "SQLServer":
                return new SQLServer();
            case "MySQL":
                return new MySQL();
            default:
                return null;
        }
    }
}


3. Create a Database interface and 4 sub-classes that implement their own connect(), add(), update(), and delete() methods. We don’t care if they are Relational or Non-relational at this point since the factory classes handle that logic.

public interface Database {
    void connect();
    void add();
    void update();
    void delete();
}
public class MongoDB implements Database {
    @Override
    public void connect() {
        System.out.println("Connected to MongoDB Non-Relational Database!");
    }

    @Override
    public void add() {
        System.out.println("Added data to MongoDB Non-Relational Database!");
    }

    @Override
    public void update() {
        System.out.println("Updated data in MongoDB Non-Relational Database!");
    }

    @Override
    public void delete() {
        System.out.println("Deleted data from MongoDB Non-Relational Database!");
    }
}
public class MySQL implements Database {
    @Override
    public void connect() {
        System.out.println("Connected to MySQL Relational Database!");
    }

    @Override
    public void add() {
        System.out.println("Added data to MySQL Relational Database!");
    }

    @Override
    public void update() {
        System.out.println("Updated data in MySQL Relational Database!");
    }

    @Override
    public void delete() {
        System.out.println("Deleted data from MySQL Relational Database!");
    }
}
public class NoSQL implements Database {
    @Override
    public void connect() {
        System.out.println("Connected to NoSQL Non-Relational Database!");
    }

    @Override
    public void add() {
        System.out.println("Added data to NoSQL Non-Relational Database!");
    }

    @Override
    public void update() {
        System.out.println("Updated data in NoSQL Non-Relational Database!");
    }

    @Override
    public void delete() {
        System.out.println("Deleted data from NoSQL Non-Relational Database!");
    }
}
public class SQLServer implements Database {
    @Override
    public void connect() {
        System.out.println("Connected to SQL Server Database");
    }

    @Override
    public void add() {
        System.out.println("Added data to SQL Server Database!");
    }

    @Override
    public void update() {
        System.out.println("Updated data for SQL Server Database!");
    }

    @Override
    public void delete() {
        System.out.println("Deleted data from SQL Server Database!");
    }
}


4. Now we can create the client class and use our factory implementation. We call the static method getFactory(“Relational”) to retrieve our DatabaseFactory method. Then we get the database object that we want to use, SQLServer and MySQL. We then do the same thing for NonRelational.

public class AbstractFactoryClient {
    public static void main(String[] args) {
        //Returns a Relational DatabaseFactory object.
        DatabaseFactory relationalFactory = DatabaseFactory.getFactory("Relational");

        //Returns a SQLServer Database object.
        Database sqlServer = relationalFactory.getDatabase("SQLServer");
        sqlServer.connect();
        sqlServer.add();
        sqlServer.update();
        sqlServer.delete();
        System.out.println();

        //Returns a SQLServer Database object.
        Database mySql = relationalFactory.getDatabase("MySQL");
        mySql.connect();
        mySql.add();
        mySql.update();
        mySql.delete();
        System.out.println();

        //Returns a Non-Relational DatabaseFactory object.
        DatabaseFactory nonRelationalFactory = DatabaseFactory.getFactory("NonRelational");

        //Returns a Mongodb Database object.
        Database mongoDb = nonRelationalFactory.getDatabase("Mongodb");
        mongoDb.connect();
        mongoDb.add();
        mongoDb.update();
        mongoDb.delete();
        System.out.println();

        //Returns a NoSQL Database object.
        Database noSql = nonRelationalFactory.getDatabase("NoSQL");
        noSql.connect();
        noSql.add();
        noSql.update();
        noSql.delete();
        System.out.println();
    }
}
Connected to SQL Server Database
Added data to SQL Server Database!
Updated data for SQL Server Database!
Deleted data from SQL Server Database!

Connected to MySQL Relational Database!
Added data to MySQL Relational Database!
Updated data in MySQL Relational Database!
Deleted data from MySQL Relational Database!

Connected to MongoDB Non-Relational Database!
Added data to MongoDB Non-Relational Database!
Updated data in MongoDB Non-Relational Database!
Deleted data from MongoDB Non-Relational Database!

Connected to NoSQL Non-Relational Database!
Added data to NoSQL Non-Relational Database!
Updated data in NoSQL Non-Relational Database!
Deleted data from NoSQL Non-Relational Database!


Process finished with exit code 0

Facade Design Pattern

 The Facade pattern is a Structural design pattern that provides a simple interface to hide the complex system underneath. It reduces dependencies to the client into a simplified interface. The client does not see what’s “under the hood” by reducing the dependencies into a simplified interface.

Facade makes APIs easier to use. Examples include a database connection API such as JDBC or a Redis caching service. You can create the underlying system to handle all of the logic that interacts with the database. Then you can have a Facade class that is called from client to Add, Update, or Select data from the database.

Let’s look at a simple implementation that allows the Client to view Upperbody and LowerBody workouts.

Here we are going to create a Workout interface with methodssetWorkout() and viewWorkout() and concrete classes LowerBody and UpperBody.  We then add the WorkoutFacade which interfaces the Workout implementations. The Client has no idea about the LowerBody and UpperBody classes. It just knows the two methods in WorkoutFacade, viewUpperBodyWorkout() and viewLowerBodyWorkout(). Let’s look at each class step by step.

  1. Create the Workout interface.
public interface Workout {

    void setWorkout();

    void viewWorkout();
}
  1. Create a simple Exercise class that contains an id and name. This is to store the exercises as an object.
public class Exercise {
    private int id;

    private String name;

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

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

}
  1. Create the Concrete classes LowerBody and UpperBody that inherit Workout. In the setWorkout method we are adding hard coded exercises to a list. In viewWorkout(), we run an enhanced for loop and print out the Exercises names.

import java.util.ArrayList;
import java.util.List;

public class LowerBody implements Workout {

    private List<Exercise> exercises = new ArrayList<>();

    /**
     * Add lower body exercises to an ArrayList
     */
    @Override
    public void setWorkout() {
        exercises.add(new Exercise(1, "Squats"));
        exercises.add(new Exercise(2, "Calf raises"));
        exercises.add(new Exercise(3, "Lunges"));
    }

    /**
     * Loop through the list of exercises and print them out
     */
    @Override
    public void viewWorkout() {
        System.out.println("LowerBody Workout");
        for(Exercise exercise : exercises){
            System.out.println("Exercise: " + exercise.getName());
        }
    }
import java.util.ArrayList;
import java.util.List;

public class UpperBody implements Workout {

    private List<Exercise> exercises = new ArrayList<>();

    /**
     * Add upper body exercises to an ArrayList
     */
    @Override
    public void setWorkout() {
        exercises.add(new Exercise(1, "Bench Press"));
        exercises.add(new Exercise(2, "Push Ups"));
        exercises.add(new Exercise(3, "Inline Bench Press"));
    }

    /**
     * Loop through the list of Exercises and print them out
     */
    @Override
    public void viewWorkout() {
        System.out.println("UpperBody Workout");
        for(Exercise exercise : exercises){
            System.out.println("Exercise: " + exercise.getName());
        }
    }
}
  1. Create the WorkoutFacade class that will hide all of the logic from the Client. Here we create viewUpperBodyWorkout and viewLowerBodyWorkout that will call setWorkout and viewWorkout. The client does not access Workout, UpperBody, or LowerBody.
public class WorkoutFacade {

    /**
     * Creates an instance of UpperBody and calls setWorkout() and viewWorkout()
     */
    public void viewUpperBodyWorkout() {
        Workout workout = new UpperBody();
        workout.setWorkout();
        workout.viewWorkout();
    }

    /**
     * Creates an instance of LowerBody and calls setWorkout() and viewWorkout()
     */
    public void viewLowerBodyWorkout() {
        Workout workout = new LowerBody();
        workout.setWorkout();
        workout.viewWorkout();
    }
}
  1. Last but not least, we will create the WorkoutClient. We create an instance of WorkoutFacade and call viewUpperBodyWorkout() and viewLowerBodyWorkout(). This will produce the following output.
public class WorkoutClient {

    public static void main(String[] args){
        WorkoutFacade workoutFacade = new WorkoutFacade();

        workoutFacade.viewUpperBodyWorkout();
        System.out.println();
        workoutFacade.viewLowerBodyWorkout();
    }
}
UpperBody Workout
Exercise: Bench Press
Exercise: Push Ups
Exercise: Inline Bench Press

LowerBody Workout
Exercise: Squats
Exercise: Calf raises
Exercise: Lunges

Adapter Design Pattern

The Adapter pattern is a Structural design pattern that works as a bridge between multiple interfaces.

The Adapter Pattern will contain a class that will interface over another class that is not compatible in your application, and will make it compatible. The Adapter pattern is useful for connecting new code to a legacy application. For example, a new data source that contains similar data but different naming conventions and types. The Adapter class will return the data to the client the same way as our original data source.

Here’s another example that might be useful. Let’s say you want to connect an HDMI device to an old Box TV. Box TVs don’t have HDMI inputs, so you would need an adapter to convert HDMI to VGA. This is how this design pattern works. You have an application (TV) and a new class (HDMI) which can’t inherit from the same interface as RCA cables. You would build an Adapter class that interfaces over HDMI that can be used by TV in order to make this connection work.

Let’s look at another example in Java.

Here we have a Company interface that contains 4 methods to be implementedWe have a CompanyDB class that inherits Company. These are essentially Getters for id, name, description and foundedDate. Let’s say we get another data source to pull from in our application CompanyOtherDB (Not a recommended class name) . This contains similar data but different names and types. We can’t directly inherit Company from this class because there are different names and types. The Adapter pattern will take care of this for us. Let’s look at each class step by step.

  1. Create the Company Interface.
public interface Company {
    int getId();
    String getName();
    String getDescription();
    String getFoundedDate();
}
  1. Create the CompanyDB class that inherits Company. Add the private variables for id, name, description and foundDate. Add the constructor as well.
public class CompanyDB implements Company {

    private int id;
    private String name;
    private String description;
    private String foundedDate;

    public CompanyDB(int id, String name, String description, String foundedDate) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.foundedDate = foundedDate;
    }

    @Override
    public int getId() {
        return id;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public String getFoundedDate() {
        return foundedDate;
    }
}
  1. Create the class CompanyOtherDB. This class acts as an interface to other data source we mentioned above. I’m sure when you look at this class, there are ways to make this class inherit Company, but that’s not the point of the pattern. The goal is here to not change any legacy code, because remember, we are adding this class after the fact.
public class CompanyOtherDB {

    private String cid;
    private String companyName;
    private String companyInformation;
    private String dateFounded;

    public CompanyOtherDB(String cid, String companyName, String companyInformation, String dateFounded) {
        this.cid = cid;
        this.companyName = companyName;
        this.companyInformation = companyInformation;
        this.dateFounded = dateFounded;
    }

    public String getCid() {
        return cid;
    }

    public String getCompanyName() {
        return companyName;
    }

    public String getCompanyInformation() {
        return companyInformation;
    }

    public String getDateFounded() {
        return dateFounded;
    }
}
  1. Create CompanyAdapter that inherits Company. In this class, we create a private instance of CompanyOtherDB and set this in the Constructor. In the override methods, we return the properties from CompanyOtherDB as if they work with Company. 
/**
 * Inherits Company
 */
public class CompanyAdapter implements Company {

    //Instance of CompanyOtherDB
    private CompanyOtherDB companyOtherDB;

    //Takes an instance as parameter
    public CompanyAdapter(CompanyOtherDB companyOtherDB) {
        this.companyOtherDB = companyOtherDB;
    }

    /**
     * Returns the cid as an integer instead of a string
     *
     * @return
     */
    @Override
    public int getId() {
        return Integer.parseInt(companyOtherDB.getCid());
    }

    /**
     * Returns companyName as Company.name
     * @return
     */
    @Override
    public String getName() {
        return companyOtherDB.getCompanyName();
    }

    /**
     * Returns companyInformation as Company.description
     * @return
     */
    @Override
    public String getDescription() {
        return companyOtherDB.getCompanyInformation();
    }

    /**
     * Returns dateFounded as Company.foundedDate
     * @return
     */
    @Override
    public String getFoundedDate() {
        return companyOtherDB.getDateFounded();
    }
}
  1. In the CompanyClient, we create an instance of Company and CompanyOtherDB. We pass companyOtherDB into CompanyAdapter and it will return us an instance of Company. That is how the Adapter Design Pattern works.
public class CompanyClient {

    public static void main(String[] args){
        //Instance of company
        Company company = new CompanyDB(1, "Amazon", "Online shopping", "1994");

        //Instance of companyOtherDB
        CompanyOtherDB companyOtherDB = new CompanyOtherDB("2", "Best Buy", "Electronics Retailer", "1966");

        //This won't work!
        //Company company2 = new CompanyOtherDB("3", "Facebook", "Social Media and Technology", "2004");
        //Error: Incompatible Types

        Company newCompany = new CompanyAdapter(companyOtherDB);

        System.out.println("Company Id from Original DB: " + company.getId());
        System.out.println("Company Name from Original DB: " + company.getName());
        System.out.println("Company Description from Original DB: " + company.getDescription());
        System.out.println("Company Founded Date from Original DB: " + company.getFoundedDate());
        System.out.println();
        System.out.println("Company Id from New DB: " + newCompany.getId());
        System.out.println("Company Name from New DB: " + newCompany.getName());
        System.out.println("Company Description from New DB: " + newCompany.getDescription());
        System.out.println("Company Founded Date from New DB: " + newCompany.getFoundedDate());
    }
}
Company Id from Original DB: 1
Company Name from Original DB: Amazon
Company Description from Original DB: Online shopping
Company Founded Date from Original DB: 1994

Company Id from New DB: 2
Company Name from New DB: Best Buy
Company Description from New DB: Electronics Retailer
Company Founded Date from New DB: 1966

Factory design pattern in Java with Example

The Factory pattern is a parameter driven creational design pattern. It is one of the most popular design patterns in Java. The Factory pattern does not expose the object instantiation logic to the client by deferring to the sub classes. All the client knows about is common interface that the factory exposes.

Lets implement an example of the Factory pattern for a simple workout application that lets you create a specific workout. We are going to create a Workout interface that contains a createWorkout() method. We will then create two concrete sub classes that inherit Workout, Upperbody and Lowerbody. We will then create a WorkoutFactory class that will be called from the client main method. WorkoutFactory will instantiate an object for us depending on the parameter that was passed into getWorkout(workoutType).

1. Create the Workout interface.

public interface Workout {
    void createWorkout();
}

2. Create the UpperBody and LowerBody sub classes that inherit Workout.

public class LowerBody implements Workout {

    @Override
    public void createWorkout() {
        System.out.println("Created Lower Body Workout that includes:");
        System.out.println("1. Squat");
        System.out.println("2. Lunges");
        System.out.println("3. Calf raises");
    }
}
public class UpperBody implements Workout {

    @Override
    public void createWorkout() {
        System.out.println("Created Upper Body Workout that includes:");
        System.out.println("1. Bench Press");
        System.out.println("2. Push ups");
        System.out.println("3. Incline Bench Press");
    }
}

3. Create the WorkoutType enum to avoid using hard coded strings.

public enum WorkoutType {

    UPPERBODY, LOWERBODY;
}

4. Create a WorkoutFactory class that will contain a static method getWorkout(workoutType). This will be static so we don’t have to create an instance of WorkoutFactory. Instead, we just reference from the class name in the client. This method will create a object for us based on the parameter that is passed.

public class WorkoutFactory {

    public static Workout getWorkout(WorkoutType workoutType) {
        switch (workoutType) {
            case UPPERBODY: {
                return new UpperBody();
            }
            case LOWERBODY: {
                return new LowerBody();
            }

            default: {
                return null;
            }
        }
    }
}

5. In your client/main method, use the WorkoutFactory class to get the workout based on the WorkoutType. The client only cares about the Workout object and doesn’t directly interface with any sub classes here.

public class Main {

    public static void main(String[] args) {
        //Retreives the UpperBody object
        Workout workout = WorkoutFactory.getWorkout(WorkoutType.UPPERBODY);
        
        //Calls createWorkout from UpperBody
        workout.createWorkout();

        //Retrieves the LowerBody object
        workout = WorkoutFactory.getWorkout(WorkoutType.LOWERBODY);

        //Calls createWorkout from LowerBody
        workout.createWorkout();
    }
}


6. Verify the output.

Created Upper Body Workout that includes:
1. Bench Press
2. Push ups
3. Incline Bench Press
Created Lower Body Workout that includes:
1. Squat
2. Lunges
3. Calf raises

 That’s the basic idea of the Factory pattern. This is a simple example but this pattern can get quite complex in a enterprise size application. This pattern is almost the opposite of the Singleton pattern. Singleton returns the same instance and has no interface or subclasses whereas the Factory pattern returns multiple instances and contains sub classes and interfaces.

Builder design pattern in Java with example.

The Builder design pattern is a creational pattern that helps limit an objects complexity. This helps immensely with immutable objects with tons of properties in your application. Immutable objects are objects that don’t change, once you create them, you can’t change them. A immutable Java object must have private final fields. You would also instantiate the object and provide all of the properties in the constructor. This means you won’t use setters to set the properties in the object. This becomes a problem when you have multiple properties and only a few are required. Lets look at a quick example.

Say you have an Employee class with five properties (id, firstName, lastName, title, birthdate) in which you want immutable. Let’s also say that you can instantiate an Employee object while only specifying the id. This would require two constructors, one that takes in all of the properties and one that takes in the id only. This can go on and can get quite messy, especially when more properties are added to the Employee object

This is when the Builder design pattern comes in handy. Lets convert this class into a builder class in steps.

public class Employee {
    
    //properties that are only accessible within the Employee class
    private final int id;
    private final String firstName;
    private final String lastName;
    private final String title;
    private final String birthdate;

    //Constructor that takes in an id only. We still have to set the other properties.
    public Employee(int id){
        this.id = id;
        this.firstName = "";
        this.lastName = "";
        this.title = "";
        this.birthdate = "";
    }
    
    //Constructor that takes in id, firstname, and lastname
    public Employee(int id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.title = "";
        this.birthdate = "";
    }

    //Constructor that takes in all properties.
    public Employee(int id, String firstName, String lastName, String title, String birthDate) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.title = title;
        this.birthdate = birthDate;
    }
}

1. Let’s remove the constructors except for the main constructor that takes in a Builder object and assign the variables like so. The builder object will contain all of the properties in the Employee which we will create next. We will also make the constructor private.

public class Employee {

    private final int id;
    private final String firstName;
    private final String lastName;
    private final String title;
    private final String birthdate;

    private Employee(Builder builder) {
        this.id = builder.id;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.title = builder.title;
        this.birthdate = builder.birthDate;
    }
}

2. Add a static inner class within Employee called Builder. Add all the properties and only make the id final because it will be set in the constructor. We then create setters within the builder class that we can only set when we create the object, I will demonstrate that shortly. The build() method will return the Employee object that we put together.

public class Employee {

    private final int id;
    private final String firstName;
    private final String lastName;
    private final String title;
    private final String birthdate;

    private Employee(Builder builder) {
        this.id = builder.id;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.title = builder.title;
        this.birthdate = builder.birthDate;
    }

    public static class Builder {
        private final int id;
        private String firstName;
        private String lastName;
        private String title;
        private String birthdate;

        public Builder(int id) {
            this.id = id;
        }

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

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

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

        public Builder setBirthDate(String birthDate) {
            this.birthdate = birthDate;
            return this;
        }

        public Employee build() {
            return new Employee(this);
        }
    }
}

3. Add your getters to the Employee class so you can access any of the properties.

public class Employee {

    private final int id;
    private final String firstName;
    private final String lastName;
    private final String title;
    private final String birthdate;

    private Employee(Builder builder) {
        this.id = builder.id;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.title = builder.title;
        this.birthdate = builder.birthDate;
    }

    public int getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getTitle() {
        return title;
    }

    public String getBirthdate() {
        return birthdate;
    }

    public static class Builder {
        private final int id;
        private String firstName;
        private String lastName;
        private String title;
        private String birthDate;

        public Builder(int id) {
            this.id = id;
        }

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

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

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

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

        public Employee build() {
            return new Employee(this);
        }
    }
}


4. Now lets build your objects! In the main method, create new Employee objects like so. You will build the Employee objects at one time and set whatever properties you want. The only required property is the id and that will be passed into the constructor. .build() will return the Employee object that you created! Once you create your employee object, you will not be able to set properties which makes it immutable!

public class Main {

    public static void main(String[] args) {
        Employee employee = new Employee.Builder(1)
                .setFirstName("Tom")
                .setLastName("Brady")
                .build();

        System.out.println("Employee Id: " + employee.getId());
        System.out.println("Employee Name: " + employee.getFirstName() + " " + employee.getLastName());

        Employee employee2 = new Employee.Builder(2)
                .setFirstName("Peyton")
                .setLastName("Manning")
                .setBirthDate("01-01-1976")
                .setTitle("Quarterback")
                .build();

        System.out.println("Employee Id: " + employee2.getId());
        System.out.println("Employee Name: " + employee2.getFirstName() + " " + employee2.getLastName());
        System.out.println("Employee Birthdate: " + employee2.getBirthdate());
        System.out.println("Employee Title: " + employee2.getTitle());

    }
}


Try creating your own objects to get a better understanding. When you want to add a new property, salary for example, you would have to add it to the Employee class, the constructor, Builder class, and your getter/setter.

public class Employee {

    private final int id;
    private final String firstName;
    private final String lastName;
    private final String title;
    private final String birthdate;
    //new property
    private final int salary;

    private Employee(Builder builder) {
        this.id = builder.id;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.title = builder.title;
        this.birthdate = builder.birthDate;
        //new property
        this.salary = builder.salary;
    }

    public int getId() {
        return id;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getTitle() {
        return title;
    }

    public String getBirthdate() {
        return birthdate;
    }

    //new getter for salary
    public int getSalary() {
        return salary;
    }

    public static class Builder {
        private final int id;
        private String firstName;
        private String lastName;
        private String title;
        private String birthDate;
        //salary property
        private int salary;

        public Builder(int id) {
            this.id = id;
        }

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

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

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

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

        //new setter for salary
        public Builder setSalary(int salary) {
            this.salary = salary;
            return this;
        }

        public Employee build() {
            return new Employee(this);
        }
    }
}