Fundamentals 7 min read

Using a Generic Builder Pattern in Java to Simplify Object Creation

This article demonstrates how a universal Builder utility can replace verbose object construction in Java, allowing developers to instantiate a class and set multiple properties—including complex collections—in a single fluent chain, while also explaining the underlying implementation and usage examples.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Using a Generic Builder Pattern in Java to Simplify Object Creation

Programmers often face the "do you have a girlfriend?" metaphor when dealing with objects that have many attributes, leading to cumbersome code with separate instantiation and setter calls.

The article first shows a traditional way of creating a GirlFriend object by calling new GirlFriend() and then invoking a series of setters for name, age, bust, waist, hips, hobby, birthday, address, mobile, email, hairColor, and gift, highlighting the maintenance difficulties.

To solve this, a generic Builder pattern is introduced that works for any class without requiring modifications to the original class or Lombok support. The Builder allows chaining of property assignments in a single statement.

public class Builder<T> {
    private final Supplier<T> instantiator;
    private List<Consumer<T>> modifiers = new ArrayList<>();
    public Builder(Supplier<T> instantiator) { this.instantiator = instantiator; }
    public static <T> Builder<T> of(Supplier<T> instantiator) { return new Builder<>(instantiator); }
    public <P1> Builder<T> with(Consumer1<T, P1> consumer, P1 p1) {
        Consumer<T> c = (instance) -> consumer.accept(instance, p1);
        modifiers.add(c);
        return this;
    }
    public <P1, P2> Builder<T> with(Consumer2<T, P1, P2> consumer, P1 p1, P2 p2) {
        Consumer<T> c = (instance) -> consumer.accept(instance, p1, p2);
        modifiers.add(c);
        return this;
    }
    public <P1, P2, P3> Builder<T> with(Consumer3<T, P1, P2, P3> consumer, P1 p1, P2 p2, P3 p3) {
        Consumer<T> c = (instance) -> consumer.accept(instance, p1, p2, p3);
        modifiers.add(c);
        return this;
    }
    public T build() {
        T value = instantiator.get();
        modifiers.forEach(modifier -> modifier.accept(value));
        modifiers.clear();
        return value;
    }
}

@FunctionalInterface
public interface Consumer1<T, P1> { void accept(T t, P1 p1); }
@FunctionalInterface
public interface Consumer2<T, P1, P2> { void accept(T t, P1 p1, P2 p2); }
@FunctionalInterface
public interface Consumer3<T, P1, P2, P3> { void accept(T t, P1 p1, P2 p2, P3 p3); }

Usage of the Builder is illustrated with a fluent chain that sets name, age, vital statistics, birthday, address, mobile, email, hair color, and multiple hobbies and gifts in one expression:

GirlFriend myGirlFriend = Builder.of(GirlFriend::new)
    .with(GirlFriend::setName, "小美")
    .with(GirlFriend::setAge, 18)
    .with(GirlFriend::setVitalStatistics, 33, 23, 33)
    .with(GirlFriend::setBirthday, "2001-10-26")
    .with(GirlFriend::setAddress, "上海浦东")
    .with(GirlFriend::setMobile, "18688888888")
    .with(GirlFriend::setEmail, "[email protected]")
    .with(GirlFriend::setHairColor, "浅棕色带点微卷")
    .with(GirlFriend::addHobby, "逛街")
    .with(GirlFriend::addHobby, "购物")
    .with(GirlFriend::addHobby, "买东西")
    .with(GirlFriend::addGift, "情人节礼物", "LBR 1912女王时代")
    .with(GirlFriend::addGift, "生日礼物", "迪奥烈焰蓝金")
    .with(GirlFriend::addGift, "纪念日礼物", "阿玛尼红管唇釉")
    .build();

The article concludes that this generic Builder supports up to three parameters per property method, is easy to extend, and dramatically reduces boilerplate when dealing with objects that have many fields.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsBuilder PatternObject ConstructionFluent API
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.