Builder pattern vs Constructor vs Setter

Builder pattern, as hinted by the name, is one of the ways to build an object.

You could have built an object with this:

// Example 1

new FlyingMachine("Boeing 787", 2, false);

Or this:

// Example 2

FlyingMachine plane = new FlyingMachine();
plane.setName("Boeing 787");
plane.setNumEngine("Boeing 787");
plane.setHasRocketBooster(false);

So, why bother using this pattern:

// Example 3

new FlyingMachineBuilder()
	.name("Boeing 787")
	.numEngine(2)
	.hasRocketBooster(false)
	.build();

Example one (Constructor based instantiation)

In example one, the object is created through constructor. There are multiple downsides with this

  • The arguments passing into the constructor are not meaningful
    • What the hell does 2 and false exactly mean?
    • In comparison the builder pattern has done a great job explaining the values .numEngine(2) and .hasRocketBooster(false)
  • The arguments are all passed in one line making it nearly impossible to read
    • You may arrange like this

        new FlyingMachine(
            "Boeing 787",
            2,
            false);
      
    • But I doubt it really improves readability

  • You cannot omit parameters
    • When one day you realize that you do not want to name that flying machine, you may choose to pass in null for name
      • new FlyingMachine(null, 2, false);
    • But using the builder pattern, you can simply remove this line: .name("Boeing 787")

Example two (Setter method)

In example two, the internal properties of the object are set by setters after instantiation. It essentially achieves the same effects as the two other methods, but it has a completely different semantic meanings. This method creates an empty object and fills in the details later, which bypasses the constructor completely and these properties cannot be used during initialization. In reality, you won’t build an aircraft without knowing what’s inside, right?

Example three (Builder method)

In example three the builder pattern is used. It is very concise and readable as compared to example one, but it also has some caveats

  • You may miss out some properties, as there is no compile time checking
    • If you miss out .name("Boeing 787"), depends on how you write your builder, but it most likely will put a null for you instead of prompting error at compile time
  • LOC will be doubled, as you have to maintain the object itself, and a copy of it in the builder
Hermann Yung's Picture

About Hermann Yung

Hermann is a software developer.

Hong Kong https://hermannyung.com

Comments