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…

Constructors vs Static Factory Method

I have wondered if this topic was relevant. I have often seen both ways to create an object. Why bother choosing between a static factory method and a constructor? It seemed to me that they do more or less the same, and the advantages of the static factor method were not so obvious. Why not using the constructor to do what it was invented for: constructing objects?! The choice did and still does feel a bit artsy (=preference). But let me list a few pros for the static method, and you may change your mind.

Advantage #1: name it!

How the heck is this more advantageous? Well, clarity. You can name your static method in a way that means what it is doing. For example, if you want to build a new garden, you can write:

Salad salad = Salad.from(lettuce);

instead of

Salad garden = new Salad(lettuce);

Hmm?? Was it better? Ok, fine. Not that much. But if you need arguments to create your object, you may have factor methods with different names. It can be particularly useful when the parameters are of the same type. For example, I want to make a salad:

public Salad(Green lettuce, Green spinach) {
// do something
}

Now if I want to make a salad with a different mix of green assuming it requires a different behavior, it will look like:

public Salad(Green lettuce, Green roman) {
// do something else
}

The signature is the same. Of course, we could figure out something else. If we have static methods, it will look more elegant:

Salad salad = Garden.makeDarkGreenMix(lettuce, spinach);
Salad salad = Garden.makeLightGreenMix(lettuce, roman);

Well, this example was not very elegant…

Advantage #2: save resources!

A static factory method does not have to create an object. The common example is the getInstance() method Java developers often use to create Singletons.

public static SaladChef getInstance() {
  if (chef == null) { // chef = private SaladChef property
    chef = new SaladChef();
  }
  return chef;
}

Another example would be a pool of connections. etc. It might help to avoid using resources.

Advantage #3: return a subclass!

A static method can return a subclass, but not the constructor. It may help to manage the types of objects return depending on the parameters.

public static Macbook buy(double amount) {
  if (amount < 1000) {
    return new MackbookAir();
  } else {
    return new MacbookPro();
  }
}

But there are two cons: classes without public or protected constructors cannot be inherited, and static factory methods are harder to find than constructors.

Honestly, I still question the systematic use of static factory methods. It is a nice way to code, but it must be used with caution. And I think it is still a matter of art.