Dezign Patterns

Builder Design Pattern

The Builder Pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.


// Product class
class Computer {
    // Required parameters
    private final String CPU;
    private final String RAM;

    // Optional parameters
    private final int storage;
    private final boolean isGraphicsCardEnabled;
    private final boolean isBluetoothEnabled;

    // Private constructor to enforce object creation via Builder
    private Computer(Builder builder) {
        this.CPU = builder.CPU;
        this.RAM = builder.RAM;
        this.storage = builder.storage;
        this.isGraphicsCardEnabled = builder.isGraphicsCardEnabled;
        this.isBluetoothEnabled = builder.isBluetoothEnabled;
    }

    // Static Builder class
    public static class Builder {
        // Required parameters
        private final String CPU;
        private final String RAM;

        // Optional parameters - initialized to default values
        private int storage = 256; // default in GB
        private boolean isGraphicsCardEnabled = false;
        private boolean isBluetoothEnabled = false;

        // Builder constructor with required parameters
        public Builder(String CPU, String RAM) {
            this.CPU = CPU;
            this.RAM = RAM;
        }

        // Setter methods for optional parameters
        public Builder setStorage(int storage) {
            this.storage = storage;
            return this;
        }

        public Builder enableGraphicsCard(boolean enabled) {
            this.isGraphicsCardEnabled = enabled;
            return this;
        }

        public Builder enableBluetooth(boolean enabled) {
            this.isBluetoothEnabled = enabled;
            return this;
        }

        // build() method to return the final Computer object
        public Computer build() {
            return new Computer(this);
        }
    }

    @Override
    public String toString() {
        return "Computer [CPU=" + CPU + ", RAM=" + RAM + ", Storage=" + storage +
               "GB, GraphicsCard=" + isGraphicsCardEnabled +
               ", Bluetooth=" + isBluetoothEnabled + "]";
    }
}

// Demo class
public class BuilderPatternDemo {
    public static void main(String[] args) {
        // Using Builder to create object
        Computer myComputer = new Computer.Builder("Intel i7", "16GB")
                                .setStorage(512)
                                .enableGraphicsCard(true)
                                .enableBluetooth(true)
                                .build();

        System.out.println(myComputer);
    }
}

✅ Advantages of the Builder Pattern

  • Helps avoid constructor overloading.
  • Improves readability when creating complex objects.
  • Makes object construction step-by-step and flexible.

❌ Disadvantages of the Builder Pattern

  • Increased Code Complexity
    It introduces additional classes (Builder, Director if used), which increases the number of code files and overall complexity. For simple objects, the Builder Pattern may be overkill.
  • Boilerplate Code
    You often end up writing a lot of repetitive code, especially for classes with many fields (getters, setters, builders, etc.).
  • Not Suitable for All Scenarios
    It's mainly beneficial for constructing complex or immutable objects. For simpler or mutable objects, regular constructors or setters may be more straightforward.
  • Requires Careful Synchronization (in multithreaded environments)
    If multiple threads share a builder instance, you must ensure it's thread-safe, which can add more overhead.
  • May Hide Dependencies
    Unlike constructors that clearly show required dependencies, builder-based instantiation may obscure what parameters are truly necessary if the builder is misused.
  • Potential for Incomplete Objects
    If the builder is used incorrectly or partially, it may result in invalid or incomplete objects unless proper validation is added in the build() method.