How to Implement the Builder Pattern with Inheritance in Java

Question

How can I implement the Builder Pattern in Java while dealing with deep inheritance trees without encountering compilation issues?

public class Rabbit {
    public String sex;
    public String name;

    public Rabbit(Builder builder) {
        sex = builder.sex;
        name = builder.name;
    }

    public static class Builder {
        protected String sex;
        protected String name;

        public Builder() { }

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

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

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

Answer

The Builder Pattern provides a flexible solution for constructing complex objects while avoiding the limitations of telescoping constructors and ensuring proper compatibility with inheritance in Java. This article explores a practical implementation for using the Builder Pattern in deep inheritance hierarchies.

public class Rabbit {
    public String sex;
    public String name;

    public Rabbit(Builder builder) {
        sex = builder.sex;
        name = builder.name;
    }

    public static <T extends Builder<T>> class Builder {
        protected String sex;
        protected String name;

        public Builder() { }

        public T sex(String sex) {
            this.sex = sex;
            return (T) this;
        }

        public T name(String name) {
            this.name = name;
            return (T) this;
        }

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

public class Lop extends Rabbit {
    public float earLength;
    public String furColour;

    public Lop(LopBuilder builder) {
        super(builder);
        this.earLength = builder.earLength;
        this.furColour = builder.furColour;
    }

    public static class LopBuilder extends Rabbit.Builder<LopBuilder> {
        protected float earLength;
        protected String furColour;

        public LopBuilder() { }

        public LopBuilder earLength(float length) {
            this.earLength = length;
            return this;
        }

        public LopBuilder furColour(String colour) {
            this.furColour = colour;
            return this;
        }

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

Causes

  • Deep inheritance hierarchies complicate constructor chaining due to method resolution issues in inheriting Builder classes.
  • Telescoping constructors lead to impractical and unreadable code when managing many parameters across derived classes.

Solutions

  • Implement a builder for each class, ensuring that the builder methods return the correct type for fluid chaining.
  • Use generics to return the derived builder type, allowing for additional parameters in derived classes without needing to override methods explicitly.

Common Mistakes

Mistake: Not ensuring that builder methods in subclasses return the correct type for chaining.

Solution: Use generics in your builder class signature to specify the builder's return type.

Mistake: Overcomplicating the builder structure with unnecessary overrides that break chaining.

Solution: Leverage the Curiously Recurring Template Pattern for cleaner implementation.

Helpers

  • Builder Pattern
  • Java inheritance
  • Builder pattern with inheritance
  • Java design patterns
  • Curiously Recurring Template Pattern
  • Object construction in Java

Related Questions

⦿How to Perform SCP Transfers Using Java: A Comprehensive Guide

Learn the best methods to perform SCP transfers in Java using JSch JSSE and Bouncy Castle. Stepbystep guide with code examples.

⦿How to Fix the 'log4j:WARN No appenders could be found for logger' Warning in web.xml Configuration

Learn how to resolve the log4j warning about missing appenders in your web.xml by properly configuring log4j properties.

⦿How to Automatically Show the Soft Keyboard for a Dialog with EditText in Android

Learn how to programmatically display the soft keyboard for an EditText in a dialog. Tips code snippets and common mistakes included.

⦿How to Resolve JPA QuerySyntaxException: 'FooBar is not mapped' Error

Learn how to fix the JPA QuerySyntaxException error with expert solutions and code examples.

⦿How to Fix Error Code=13 When Starting Eclipse After Java Update

Learn how to resolve the Eclipse error code13 issue after updating Java to version 1.8 u25 with this detailed guide.

⦿Best Practices for Organizing Java Unit Test Directory Structure

Learn how to effectively organize your Java unit test directory structure and methods for testing private members in your classes.

⦿Why is the @BeforeEach Method Not Invoked in My JUnit 5 Test?

Discover why your BeforeEach method isnt being invoked in JUnit 5 tests and how to resolve common issues.

⦿What Are the Best Java Libraries for Fuzzy String Search?

Explore top Java libraries for fuzzy string searching including pros and cons of each. Optimize your text matching with expert recommendations.

⦿Why Does InetAddress.getLocalHost() Take More Than 30 Seconds to Execute?

Discover why InetAddress.getLocalHost may run slowly and how to troubleshoot it effectively.

⦿How to Autowire RestTemplate in Spring Using Annotations

Learn how to autowire RestTemplate in Spring with annotations and resolve common NoSuchBeanDefinitionException errors.

© Copyright 2025 - CodingTechRoom.com