Skip to content
Advertisement

Java: Abstract class with builder pattern

I hope this isn’t a duplicate; I know there are some similarly named questions but none of them seemed to solve my problem.

I have multiple classes that are exactly the same – apart from one specific method. So I decided to create one abstract parent class, let’s call it A. A runs all the code and has one method calculate(), that all subclasses implement.

So far so good. My problem is, that all subclasses take a lot of optional parameters, so instead of creating lots of different constructors I decided to use the following builder pattern:

public abstract class A {
   private int foo;
   private int bar;
   
   public static class Builder {
      private int foo;
      private int bar;
      
      public Builder(int foo) {
         this.foo = foo;
      }
    
      public Builder bar(int bar) {
         this.bar = bar;
         return this;
      }
 
      public A build() {
         return new A(this);
      }
   }

   private A(Builder builder) {
      this.foo = builder.foo;
      this.bar = builder.bar;
   }
}

I used this specific pattern throughout my project a lot and it worked fine, as long as the class is not abstract. The problem is that the build() messages returns an A object, but A, of course, can not be instantiated.

So to me it seems there are two solutions, but none of them seem optimal:

  1. Move Builder class down to the subclasses of A, so they can be instantiated. This would result in a lot of redundant code, since all attributes the builder sets are identical.

  2. Make A not abstract. But that would allow another user to instantiate it, even though that’s not its intended purpose.

Am I missing something? I feel like there should be a more elegant solution, but I cant think of one at the moment… Thank you

Advertisement

Answer

As there are no instances of A (being an abstract class), an A builder can only build instances of some none-abstract subclass of A. Having a builder at the level of an abstract class typically lets the builder decide which concrete subclass of A to instantiate, depending on parameters collected in the building process.

The idea behind that approach is that the caller isn’t interested in the concrete class, just in the fact that it’s an A subclass, and the builder is free to provide the instance that best suits the building request.

If your situation is different, in that the user wants to decide on the resulting class, then you’d create multiple builders, and maybe have them inherit common parts from an (abstract) parent builder. But in such a situation, ask yourself whether using a builder has enough benefit over directly using a constructor to warrant the additional boilerplate code. And with constructors, you immediately get inheritance for free.

The fact that something like a “builder pattern” exists doesn’t imply that it fulfills your requirements.

So, to summarize the options I see:

  • Have a builder at the A level that decides (in the build() method) which subclass to instantiate (if your users aren’t interested in the concrete class, just “any A implementation”),
  • Have multiple builders, one for each subclass. To avoid code repetition, they can inherit from an abstract builder at the A class level. This gives complete control over the resulting type to the user.
  • Ignore the builder pattern, and use plain old constructors.
8 People found this is helpful
Advertisement