The Fluent Builder as Solution to the Builder Pattern and Inheritance

What a title! If you do not know what the builder pattern is, you can look at my post here. A builder can be helpful, but you quickly realize it is painful to handle this pattern with inheritance.

Let’s use this simple example: we want to create classes representing a SUV and a coupe.

public class Car { 

    private Color color;
    private Engine engine;

}

public class SUV extends Car { 

   private FourWheelDriveSystem wdSystem;

}

public class Coupe extends Car {  

   private Door[] twoDoors;

}

We want to use the builder pattern to instantiate SUV and Coupe objects. We could simply duplicate the code from the Car Builder in SUV and Coupe. It may be ok if there are not many properties. But if we want to avoid duplicating, we can create a Car, SUV and Coupe Builders:

public class Car {

  private Color color;
  private Engine engine;

  public static class Builder { // see post on builder pattern for more details
     private Color color;
     private Engine engine;

     public Builder withColor(Color color) { ... }
     public Builder withEngine(Engine engine) { ... }
     public Car build() { ... } 
  }

}

public class SUV extends Car {

   private FourWheelDriveSystem wdSystem;

   public static class Builder extends Car.Builder { 
     private FourWheelDriveSystem wdSystem;

     public Builder withWdSystem(FourWheelDriveSystem wdSystem) { ... }
     public SUV build() { ... }
   }
}

public class Coupe extends Car {

   private DoorSystem twoDoors;

   public static class Builder extends Car.Builder {
      private DoorSystem twoDoors;

      public Builder withTwoDoors(DoorSystem twoDoors) { ... }
      public Coupe build() { ... }
   }

}

So far so good. However, this code fails:

new SUV.Builder()
  .withColor(color) // returns a Car.Builder
  .withWdSystem(wdSystem) // do not compile because the function belongs to SUV.Builder
  .withEngine(engine)
  .build(); // would return a Car object, not a SUV...

One solution is to use Recursive Generics:

// in Car class
public static class Builder<SELF extends Car.Builder<SELF>> {

  public SELF withColor(Color color) { 
    this.color = color;
    return (SELF) this;
  }
  ...
}

// in SUV class
public static class Builder extends Car.Builder<Builder> {

  public Builder withWdSystem(FourWheelDriveSystem wdSystem) { 
     this.wdSystem = wdSystem;
     return this;
  }

}

Now the code works:

new SUV.Builder()
   .withColor(color) // now returns a SUV.Builder
   .withWdSystem(wdSystem) 
   .withEngine(engine)
   .build(); // would return a SUV object

Et voila! But it takes a bit of brain power to understand for a programmer who has not developed the code to understand what the builder does…

Leave a comment

Design a site like this with WordPress.com
Get started