The Builder Pattern in Java, and Dart Cascades
Tags: java, dart, patterns, beginners
Published: 2017-12-06 16:04:20

---
title: The Builder Pattern in Java, and Dart Cascades
published: true
description: Let's look at how to build better objects in Java, and how Dart's built-in syntactic sugar helps us eliminate the need for Builders.
tags: #java, #dart, #patterns, #beginners
---

Object construction is something that everyone will have to do in a language that has object-oriented paradigms. However, when your objects have a lot of members and are subject to change, how do you create a robust API that protects your consumers from non-passive changes? How do you avoid having multiple constructors that allow your users to construct the objects differently (what I refer to as _constructor hell_)?

## An Example

Let's say that you're opening up your own pizza chain, and you want to write a Java application that allows users to create their own pizza.

The most logical thing for you to do is to create a `Pizza` class that allows you to encapsulate the concept of a pizza:

```java
public class Pizza {
    private Collection<String> toppings;
    private String sauce;
    private boolean hasExtraCheese;
}
```

This looks ok right? And we can create getter and setter methods for these members that allow us to alter the state of the object:

```java
//... other code

public Collection<String> getToppings {
    return this.toppings;
}

public void setToppings(Collection<String> toppings) {
    this.toppings = toppings;
}

// ... other setters and getters
```

Not too bad... But how does one construct one of these things?? Well, the simplest answer would be to set everything by hand:

```java
final Pizza pizza = new Pizza();
pizza.hasExtraCheese(true);
pizza.setSauce("garlic");
List<String> toppings = new ArrayList<String>();
toppings.add("pepperoni");
pizza.setToppings(toppings);
```

Which isn't too bad... But that's a lot of code... We could create a constructor:

```java
public Pizza(Collection<String> toppings, String sauce, boolean hasExtraCheese) {
    // and then you set stuff...
}
```

Which makes the code look more like this:

```java
List<String> toppings = new ArrayList<String>();
toppings.add("pepperoni");
final Pizza pizza = new Pizza(toppings, "marinara", false);
```

Which isn't too bad... But what if I don't care about specifying if I need extra cheese? And maybe it would be convenient to provide a means of constructing a pizza with a default sauce. At this point, you might be tempted to do the following:

```java
public Pizza(Collection<String> toppings) {
    // default the sauce and extra cheese
}

public Pizza(String sauce, boolean hasExtraCheese) {
    // default toppings as empty
} 

//... potentially many more constructors
```

You could make so many different constructors as a convenience (anybody who writes [Swift](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html) get that one?).

Wanna know what makes this constructor hell not so great? _When people start wanting to customize their pizza crust._

```java
public class Pizza {
    private Collection<String> toppings;
    private String sauce;
    private boolean hasExtraCheese;
    private String crust; // OH NO, NEW THING I DIDN'T PLAN FOR!!! WE'RE DOOMED!
}
```

Who wants to go write a dozen constructors to support initializing a `Pizza` with an optional crust? Who wants to go create exponentially more after marketing tells you people want to customize their pizza with sauce drizzles and crust dust as a means to compete with Pizza Hut?

...

Nobody? Cool, let's write a Builder instead.

## Builder Pattern

The Builder pattern allows you to _build_ objects rather than _construct_ them. You provide an API in your builder that allows you to set all of the properties of a `Pizza`, and then the builder will build the object for you:

```java
public class PizzaBuilder() {
    private Collection<String> toppings;
    private String sauce;
    private boolean hasExtraCheese;
    private String crust;
    
    public PizzaBuilder withToppings(Collection<String> toppings) {
        this.toppings = toppings;
        return this;
    }

    // ... create a "with" method for each member you want to set

    public Pizza build() {
        final Pizza pizza = new Pizza();
        // set the pizza properties
        return pizza;    
    }
}
```

This makes your `Pizza` creation **much easier**, it ends up **looking cleaner**, it can help make your `Pizza`s **immutable**, and your code is now much more **passive to changes**:

```java
final Pizza pizza = new PizzaBuilder()
    .withHasExtraCheese(true)
    .withSauce("marinara")
    .withCrust("pan")
    .withToppings(new ArrayList<String>())
    .build();
```

Now, when people consume your `Pizza`-making API, if you add more functionality, then you won't need to create more constructors, and others won't need to be concerned about implementing the new functionality if they don't have to.

## How Dart Addresses This

Dart has some excellent syntax that allows us to skip the creation of builders and prevents us from getting into constructor hell. Let's look at the same `Pizza` class in Dart:

```dart
class Pizza {
    List<String> toppings;
    String sauce;
    bool hasExtraCheese;
}
```

One cool thing about Dart is that [instance variables](https://www.dartlang.org/guides/language/language-tour#instance-variables) implement implicit getters and setters. If the instances are final, setters don't get generated.

And we're done! Our consumers can create `Pizza` instances and are already guarded against non-passive changes!

...

No, I'm dead serious. Your job is done. You did the needful. You can go home.

Dart has an excellent feature called [cascade notation](https://www.dartlang.org/guides/language/language-tour#cascade-notation-) that allows you to invoke getters, setters, and methods on object instances to instantiate them:

```dart
// don't mind me, just constructing a pizza...
var pizza = new Pizza()
    ..toppings = ['pepperoni', 'mushrooms']
    ..sauce = 'spaghetti'
    ..hasExtraCheese = true;
```

Looks a lot like a builder, but it really isn't. Now, if we add more instance variables, the above code still works correctly. Our consumers can add crust later if they want, _no reassembly required_.

I hope you enjoyed looking at the builder pattern, and I hope that this has sparked your interest in Dart!