DEV Community

Charles Koffler
Charles Koffler

Posted on

Builder Pattern in Clprolf — Example with a House

Following our posts on Adapter, Strategy, Observer, Factory, and Proxy, let’s now explore the Builder Pattern in Clprolf.

In traditional OOP, the Builder pattern was invented to avoid telescoping constructors:
classes with too many parameters, often optional, that force you to write many overloaded constructors.
The result is confusing, and the object ends up polluted with initialization logic.

In Clprolf, the solution is clearer:

  • The Builder is an agent dedicated to dynamic construction.
  • The Product is usually a simu_real_obj (an object from the real domain we simulate) or sometimes an abstraction.
  • The Builder composes and prepares the product step by step, then delivers it with build().

Example: Building a House

Imagine we need to create a House with optional attributes.
Instead of multiple constructors, we use a Builder Agent.


The Product (Simulated Real Object)

public simu_real_obj House {
    String name;
    int floors;
    boolean garage;

    public void show(){
        System.out.println("House " + name + ", " + floors + " floors, garage: " + garage);
    }
}
Enter fullscreen mode Exit fullscreen mode

The Builder Agent (Composition)

public agent HouseBuilder {
    private House house = new House(); // composition

    public HouseBuilder withName(String name){
        house.name = name;
        return this;
    }

    public HouseBuilder withFloors(int floors){
        house.floors = floors;
        return this;
    }

    public HouseBuilder withGarage(boolean garage){
        house.garage = garage;
        return this;
    }

    public House build(){
        if(house.name == null){
            throw new IllegalStateException("House must have a name");
        }
        return house;
    }
}
Enter fullscreen mode Exit fullscreen mode

👉 Here:

  • House is a simu_real_obj — the product we want to build.
  • HouseBuilder is an agent that prepares it step by step.
  • No duplication of attributes: the Builder works directly with the object in composition.

The Launcher

public worker_agent Launcher {
    public static void main(String[] args){
        House villa = new HouseBuilder()
            .withName("Villa Clprolf")
            .withFloors(2)
            .withGarage(true)
            .build();

        villa.show();
    }
}
Enter fullscreen mode Exit fullscreen mode

Console Output

House Villa Clprolf, 2 floors, garage: true
Enter fullscreen mode Exit fullscreen mode

When to Use Builder

The Builder is not for every object.
It is useful when:

  • The product has many parameters, some optional.
  • You want all construction possibilities, without cluttering the class.
  • You need to check conditions before instantiation.

For simpler objects, a constructor is enough.


Factory vs Builder in Clprolf

Both Factory and Builder are creational patterns, but they solve different problems:

Factory (abstraction) Builder (agent)
Decides which variant of an object to create Prepares how to construct an object step by step
Often returns different implementations Always prepares the same type, with variations
Example: CarFactoryElectricCar or DieselCar Example: HouseBuilder → builds one House with flexible options
Declension: abstraction Declension: agent

👉 Factory answers “which object?”
👉 Builder answers “how to assemble it?”


Fluent Builder

The most common style is the Fluent Builder, where each method returns the builder itself.
This allows chaining calls naturally:

House villa = new HouseBuilder()
    .withName("Fluent Villa")
    .withFloors(3)
    .withGarage(false)
    .build();
Enter fullscreen mode Exit fullscreen mode

This style makes the Builder look almost as natural as a constructor, but without the complexity of overloaded constructors.


Internal Builder (Variation)

Sometimes, the Builder is placed inside the product class.

public simu_real_obj House {
    String name;
    int floors;
    boolean garage;

    public void show(){
        System.out.println("House " + name + ", " + floors + " floors, garage: " + garage);
    }

    public static agent Builder {

        private House house;

        public Builder(){
            reset();
        }

        public void reset(){
            house = new House();
            // default values
            house.floors = 1;
            house.garage = false;
        }

        public Builder withName(String name){
            house.name = name;
            return this;
        }

        public Builder withFloors(int floors){
            house.floors = floors;
            return this;
        }

        public Builder withGarage(boolean garage){
            house.garage = garage;
            return this;
        }

        public House build(){
            if(house.name == null){
                throw new IllegalStateException("House must have a name");
            }
            House product = house;
            reset();
            return product;
        }
    }

}
Enter fullscreen mode Exit fullscreen mode

Usage:

House villa = new House.Builder()
    .withName("Internal Builder Villa")
    .withFloors(2)
    .withGarage(true)
    .build();
Enter fullscreen mode Exit fullscreen mode

👉 In Clprolf, even as an internal class, the Builder remains a separate agent, so roles are explicit.


Conclusion

In Clprolf, the Builder Pattern becomes clearer:

  • The product is usually a simu_real_obj (a real-world object simulated in code).
  • The Builder is an agent that constructs it step by step.
  • Fluent style makes the usage compact and natural.
  • And the separation of roles is explicit: one class simulates the object, the other acts as the constructor agent.

✨ The Builder is not for every case, but when you need all construction possibilities, it gives you clarity and control — without cluttering your product objects.


Top comments (0)