The Builder Pattern in Dart
Tags: dart, flutter, patterns, webdev
Published: 2020-02-28 09:05:42

---
title: The Builder Pattern in Dart
published: true
description: 
tags: #dart #flutter #patterns #webdev
---

Everyone coming from OOP programming have heard about the builder pattern... "and its intent of separating the construction of a complex objets from its representation, providing a flexible solution for creating objects to programmers".

My first steps with OOP was with Java and trust me it was while ago. Nowadays, I pretty much code in Javascript (React & Typescript) and a week ago I decided to give a try Dart...!


*Okay buddy, but...! I know, I know "Builder pattern"!*

There is a great [Dev article](https://dev.to/jvarness/the-builder-pattern-in-java-and-dart-cascades-5l7) introducing [cascade notation](https://dart.dev/guides/language/language-tour#cascade-notation-) in Dart, which cover in somehow an approach to the Builder pattern, but in my desire to discover more about this new language this post explain my own implementation of the Builder pattern in Dart.

> My example is based on the 🍕 `class` from the mentioned article, in this way it will help to connect both articles and if you have read it before this one, you will be already familiar with the code

> If you prefer to go directly to the code and see what my brain coded, see this [gist](https://gist.github.com/inakiarroyo/e8cfd95b4c3a5538c27d96970e2956af)

## First attempts

Thinking on a common implementation of a Builder pattern in _Java_ my first attempt was to write a `class` that contained a `static` nested builder class such as:

```dart
class Pizza {
  Pizza._();

  static class Builder {
    Builder();
  }
}
```

Should be easy... but _"arg!!"_ my first error came up: _classes can't be declared inside other classes_

So, researching about this error my surprise was that Dart doesn't allow to declare [nested classes](https://github.com/dart-lang/sdk/issues/3755). Okay, well... maybe just use the cascade notation and get this sorted out.

_NO WAY... I need to find a work around it! 
but why? what are the reasons...?_

* Immutability issues
  * cascade notation allows to modify/mutate the value of the `class Pizza` attributes ones it has been instantiated/"built" (classes in Dart auto-create _setters_ methods for each of their attributes if they are not declared as `final`). So, using it breaks one of the purpose of the builder pattern: build it once and keep it as immutable across its life cycle.
  * Those attributes declared as `final` could not be modified by the cascade notation (there is not _setter_ method), so they will need to be initialised into the constructor... _mmm this smells as another reason of why the builder pattern was created, isn't it?_
* Messy code
  * there is not separation between those methods used for building the `Pizza` object and those which express what a pizza could "do" or what could be done with a Pizza.


## Dart Builder pattern

There are two main code blocks:
* _pizza.dart_ which contains the `class Pizza` & `class PizzaBuilder` code
* _test.dart_ which contains code explaining how to use them and showing the output of the `print` statements from the _test.dart_ code blocks


```dart
/// pizza.dart

class Pizza {
  final String sauce;
  final List<String> toppings;
  final bool hasExtraCheese;
  
  Pizza._builder(PizzaBuilder builder) : 
    sauce = builder.sauce,
    toppings = builder.toppings,
    hasExtraCheese = builder.hasExtraCheese;
}

class PizzaBuilder {
  static const String neededTopping = 'cheese';
  
  final String sauce;

  PizzaBuilder(this.sauce);

  List<String> toppings;
  bool hasExtraCheese;

  void setToppings(List<String> toppings) {
    if (!toppings.contains(neededTopping)) {
      throw 'Really, without $neededTopping? :(';
    }
    
    this.toppings = toppings;
  }
  
  Pizza build() {
    return Pizza._builder(this);
  }
}
```

### `class Pizza`

Ups:
* Clean code and concept separation
* `class Pizza` declares their attributes as `final`, so they can't be modified ones they have been instantiated or built
* `class Pizza` redefines its default constructor, declaring a [named constructor](https://dart.dev/guides/language/language-tour#named-constructors) `_builder`, which warns devs that this class must be built through the Builder pattern. In addiction, it is marked as private (library scoped) with the `_` and it does not allow to create direct instances of itself as there is not default constructor defined
* Injects the `PizzaBuilder` as attribute of the `Pizza` constructor initialing the `final` attributes invoking a superclass constructor using the [initializer-list](https://dart.dev/guides/language/language-tour#initializer-list) mode
* Because attributes are declared as `final` they don't need to be private, so we could access them directly ones the `Pizza` object is built with no extra _getters_ code inside the class

### `class PizzaBuilder`

Ups:
* Clean code and concept separation
* `PizzaBuilder` only knows about how to build a `Pizza`, nothing else
* It allows to build a `Pizza` object using specific methods as `setToppings` (for a fine customisation) or directly accessing the attributes by the cascade notation mode without the verbose _setters & getters_ code 
* Having it as external class allows to reuse a `PizzaBuilder` instance for building more than one `Pizza` object
* It combines the Builder pattern standards with the fast and flexible Dart cascade notation technique


```dart
/// test.dart
print('___PIZZA BBQ___');

Pizza pizza = (
  PizzaBuilder('bbq')
    ..setToppings(['tomato', 'cheese', 'chicken'])
    ..hasExtraCheese = true
  ).build();
  
print(pizza.sauce);           // bbq
print(pizza.toppings);        // [onion, cheese, chicken]
print(pizza.hasExtraCheese);  // true
```
_Pizza BBQ was ordered with a nice bbq sauce, great toppings and an amazing extra of cheese._

The `PizzaBuilder` uses the cascade notation pattern to build the `Pizza`:
* uses the customise `setToppings` method which verify the needed toppings are part of the included ones
* set the `hasExtraCheese` accessing directly the attribute, because there is no need to create a verbose _setter_ method

Fast, easy and flexible 🍕!

```dart
print('___PIZZA Carbonara___');

Pizza pizza2 = (
  PizzaBuilder('cream')
  ..hasExtraCheese = true
).build();

print(pizza2.sauce);          // cream
print(pizza2.toppings);       // null
print(pizza2.hasExtraCheese); // true
```

_This Pizza Carbonara is a bit weird, don't you think it?... the employee forgot to add toppings to it!_

...but for the coding world everything is good, nothing breaks, you can build your Pizza as you want!


```dart
print('___PIZZA Margherita___');

Pizza pizza3 = (
  PizzaBuilder('olive-oil')
  ..setToppings(['PINEAPPLE', 'tomato'])
  ..hasExtraCheese = false
).build();
                              // Uncaught Error: Really, without cheese? :( 

print(pizza3.sauce);          // No output due to Uncaught Error
print(pizza3.toppings);       // No output due to Uncaught Error
print(pizza3.hasExtraCheese); // No output due to Uncaught Error
```

_Hell yeah, the amazing and famous Neapolitan pizza Margherita has been ordered!_
_Melted Mozzarella cheese... wait! what? Oh, God! the employee has added PINEAPPLE as topping instead of cheese!_

...but building the Pizza by cascade notation pattern using a custom `setToppings` method allowed the restaurant to detect that the employee made a mistake showing `Really, without cheese? :(` on the system

## Conclusion
_The employee always said he was from Naples and the real Pizza was made with pineapple... :)_

As I tried to explained above, combining different techniques and patterns such as Builder one along with the OOP standards and the cascade notation from Dart, we have been able to build and easy, flexible and powerful Dart Builder pattern.

_...pineapple out! cheese forever!_