What is a nested class? Builder pattern with nested class

A nested class is a class defined within another class. In many object-oriented programming languages like Java, C#, and Python, a nested class (or inner class) is used to logically group classes that are only used in
one place. It helps to create more readable and maintainable code by keeping related classes together.

Types of Nested Classes

  1. Static Nested Class (Java/C#): This type of nested class does not have access to the instance members of the outer class. It behaves more like a static member of the outer class and is often used when the nested
    class is logically tied to the outer class but does not depend on its instance data.

  2. Non-static Nested Class (Inner Class): This has access to the outer class’s instance members (including private fields). It’s used when the nested class needs to interact with the enclosing class.


When to Use a Nested Class

  • Encapsulation: If a class is only useful within the context of another class, nesting it can improve encapsulation. It makes sense when the inner class is tightly coupled with its outer class and is not meant to be
    used elsewhere.
  • Logical grouping: Helps to group classes that are logically dependent or are helpers of the outer class, which improves code readability.
  • Avoid namespace pollution: Nested classes prevent unnecessary pollution of the outer namespace by hiding the inner class’s implementation details.
  • Use in specific patterns: Some design patterns like the Builder pattern use nested classes to handle complex object creation.

Nested Class in the Builder Pattern

In the Builder pattern, a nested class is commonly used to provide a way to construct a complex object step by step. Here’s why:

  1. Logical Grouping: The Builder class is often tightly coupled with the outer class (the object it is constructing). Grouping them together in one place makes sense as the Builder class
    is not meant to be reused elsewhere.

  2. Simplified Construction: The nested Builder class allows us to create an instance of the outer class in a controlled and flexible manner. Instead of having a constructor with many parameters, the
    Builder pattern makes it possible to provide readable and easy-to-follow chained method calls.

  3. Immutability: Often in the Builder pattern, the outer class is made immutable. The builder class can then be used to gradually set properties before producing an instance of the immutable outer class.

public class Car {
    // Required parameters
    private String engine;
    private String transmission;

    // Optional parameters
    private boolean airConditioning;
    private boolean sunroof;

    // Private constructor, so the object can only be built through the Builder
    private Car(CarBuilder builder) {
        this.engine = builder.engine;
        this.transmission = builder.transmission;
        this.airConditioning = builder.airConditioning;
        this.sunroof = builder.sunroof;
    }

    // Nested static builder class
    public static class CarBuilder {
        // Required parameters
        private String engine;
        private String transmission;

        // Optional parameters
        private boolean airConditioning = false;
        private boolean sunroof = false;

        public CarBuilder(String engine, String transmission) {
            this.engine = engine;
            this.transmission = transmission;
        }

        public CarBuilder setAirConditioning(boolean airConditioning) {
            this.airConditioning = airConditioning;
            return this;
        }

        public CarBuilder setSunroof(boolean sunroof) {
            this.sunroof = sunroof;
            return this;
        }

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

// Usage
Car car = new Car.CarBuilder("V8", "Automatic")
                .setAirConditioning(true)
                .setSunroof(true)
                .build();