18 - Builder
Tags: flutter, dart, oop, programming
Published: 2021-05-17 13:56:05

Previously in the series, I have analysed a relatively complex, but very practical and useful structural design pattern — Bridge. This time I would like to represent a design pattern, which divides the construction of a complex object into several separate steps. It is a creational design pattern called Builder.

## Table of Contents

* What is the Builder design pattern?
* Analysis
* Implementation
* Your Contribution

## What is the Builder design pattern?

![If Bob The Builder Were A Programmer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xmw60tgptct6kaczkhig.png)

**Builder** is a creational design pattern, which intention in the [GoF book](https://en.wikipedia.org/wiki/Design_Patterns) is described like this:

> Separate the construction of a complex object from its representation so that the same construction process can create different representations.

The intention could be split into two parts:

> Separate the construction of a complex object from its representation…

You should have already noticed this in the majority of the design patterns overviewed in the series, maybe in a slightly different form, e.g. *separate the abstraction from its representation*. In this case, one of the main purposes of the Builder design pattern is to separate the creation process (logic) of a complex object from the object (data) itself. What is a complex object? Well, there is no specific point or any criteria of the object when you could say that it is complex. Usually, an object could be considered as complex when the object’s creation does not simply end with calling its constructor — additionally, you should set some extra specific parameters, call additional methods.

Ok, at this point we have a complex object, we can create it by using some additional parameters and/or methods — why we need any additional abstraction on top of that, why we should separate this creation process from the object at all?

> … so that the same construction process can create different representations.

Ahh, that’s the point! To understand it better, let’s say we are building a house. To build a house (object), the construction steps (build logic) are pretty much the same — you need the foundation, floor, some walls, doors, windows, a roof, etc. Even though the construction process of the house is the same, each of these steps could be adjusted, hence the final result would look completely different. And that is the main idea of the Builder design pattern — abstract the object’s creation process so that constructions steps could be adjusted to provide a different representation (final result).

The Builder design pattern moves the object construction code out of its own class to separate objects called *builders*. Each of these builders follows the same interface and implements separate object’s construction steps. That is, if you want a different object’s representation, just create a different *builder* class and implement these construction steps correspondingly. Also, there is one additional layer in the Builder design pattern — *Director*. The *Director* is a simple class that is aware of the *Builder* interface and defines the order in which to execute the building steps. This class is not mandatory, though, but it hides the details of product construction from the client code.

I know, the structure of the Builder design pattern is quite complex, so let’s move to the analysis and implementation parts to understand it better!

## Analysis

The general structure of the Builder design pattern looks like this:

![Builder Class Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vmrwwxsmdtaps916mnxx.png)

* *Builder* — defines an abstract interface that is common to all types of builders for creating parts of a *Product*;
* *Concrete Builder* — provides a specific implementation of the construction steps. Also, it defines and keeps track of the *Product* it creates;
* *Director* — constructs an object using the *Builder* interface, defines the order in which the construction steps are called;
* *Product* — represents the complex object under construction, exposes interface/methods for assembling the parts into the final result;
* *Client* — associates the specific *Builder* object with the *Director*. Later, a *Product* object is created by calling the *Director* class instance.

### Applicability

The Builder design pattern should be used when you notice multiple constructors of the same class referencing each other. For instance, you have a constructor with multiple optional parameters. Some of these parameters have default values, so you create several shorter constructors with fewer parameters, but still refer to the main one. By using the Builder design pattern, you are building objects step by step only using those steps that are really needed — you do not need to cope with the problem of multiple constructors with optional parameters anymore.

As already mentioned, this pattern should be used when you want to create different representations of some product. That is, the pattern could be applied when the construction steps are similar, but they differ in the details. The builder interface defines those steps (some of them may even have the default implementation) while concrete builders implement these steps to construct a particular representation of the product.

Finally, the Builder design pattern is useful when the algorithm for creating a complex object should be independent of the parts that make up the objects and how they are assembled. In simple words, it is just a simple extraction of the object’s creation logic from its own class. Therefore, the construction algorithm could evolve separately from the actual product it provides, the modification of this process does require changing the object’s code.

## Implementation

![Let's Do This](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sostrjdufnl7esi56wpf.gif)

This time, the implementation part is very straightforward — we will use the Builder design pattern to implement the build process of *McDonald’s* burgers.

As you may know, *McDonald’s* menu contains multiple burgers (regular burger, cheeseburger, Big Mac just to name a few). All of these burgers use the very same products, just the ingredients list is different:
* Regular burger — buns, beef patty, ketchup, mustard, grill seasoning, onions, pickle slices;
* Cheeseburger — buns, beef patty, cheese, ketchup, mustard, grill seasoning, onions, pickle slices;
* *Big Mac* — buns, cheese, beef patty, Big Mac sauce, grill seasoning, onions, pickle slices, shredded lettuce.

As you can see, by changing the build process of the burger (changing ingredients), we completely change the final result. Also, at any moment there could be a requirement to add a new burger to the menu. Finally, the user-friendly UI should be implemented where you can select a burger from the menu and see its price, ingredients and allergens list.

For this problem, the Builder design pattern is a great option since we can define different *builder* classes which build specific burgers. Also, if a new burger should be added to the menu at any point, we can simply introduce another *builder* class to cope with this change. Let’s check the class diagram first and then implement the pattern.

### Class diagram

The class diagram below shows the implementation of the Builder design pattern:

![Builder Implementation Class Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fo43fjetxhvs945j57jk.png)

The *Ingredient* is an abstract class that is used as a base class for all the ingredient classes. The class contains *allergens* and *name* properties as well as *getAllergens()* and *getName()* methods to return the values of these properties.

There are a lot of concrete ingredient classes: *BigMacBun*, *RegularBun*, *BeefPatty*, *McChickenPatty*, *BigMacSauce*, *Ketchup*, *Mayonnaise*, *Mustard*, *Onions*, *PickleSlices*, *ShreddedLettuce*, *Cheese* and *GrillSeasoning*. All of these classes represent a specific ingredient of a burger and contains a default constructor to set the *allergens* and *name* property values of the base class.

*Burger* is a simple class representing the product of a builder. It contains the *ingredients* list and *price* property to store the corresponding values. Also, the class contains several methods:

* *addIngredient()* — adds an ingredient to the burger;
* *getFormattedIngredients()* — returns a formatted ingredients’ list of a burger (separated by commas);
* *getFormattedAllergens()* — returns a formatted allergens’ list of a burger (separated by commas);
* *getFormattedPrice()* — returns a formatted price of a burger;
* *setPrice()* — sets the price for the burger.

*BurgerBuilderBase* is an abstract class that is used as a base class for all the burger builder classes. It contains *burger* and *price* properties to store the final product — burger — and its price correspondingly. Additionally, the class stores some methods with default implementation:

* *createBurger()* — initialises a *Burger* class object;
* *getBurger()* — returns the built burger result;
* *setBurgerPrice()* — sets the price for the burger object.

*BurgerBuilderBase* also contain several abstract methods which must be implemented in the specific implementation classes of the burger builder: *addBuns()*, *addCheese()*, *addPatties()*, *addSauces()*, *addSeasoning()* and *addVegetables()*.

*BigMacBuilder*, *CheeseburgerBuilder*, *HamburgerBuilder* and *McChickenBuilder* are concrete builder classes that extend the abstract class *BurgerBuilderBase* and implement its abstract methods.

*BurgerMaker* is a director class that manages the burger’s build process. It contains a specific builder implementation as a *burgerBuilder* property, *prepareBurger()* method to build the burger and a *getBurger()* method to return it. Also, the builder’s implementation could be changed using the *changeBurgerBuilder()* method.

*BuilderExample* initialises and contains the *BurgerMaker* class. Also, it references all the specific burger builders which could be changed at run-time using the UI dropdown selection.

### Ingredient

An abstract class that stores the allergens, name fields and is extended by all of the ingredient classes.

![ingredient.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4qscc2svnc8iejy9d73.png)

### Concrete ingredients

All of these classes represent a specific ingredient by extending the *Ingredient* class and specifying an allergens’ list as well as the name value.

* Big Mac Bun

![big_mac_bun.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/box2rppwj16k9japf031.png)

* Regular Bun

![regular_bun.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3z3ys4y4cstb05ncquqx.png)

* Cheese

![cheese.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4i4jv9s4jlnmrzafl7cm.png)

* Grill Seasoning

![grill_seasoning.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ws190zvruwohkbn5nksa.png)

* Beef Patty

![beef_patty.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uv7vti9wobqc88pbsr4p.png)

* McChicken Patty

![mc_chicken_patty.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmmuzf5m8ortp6a5ucm5.png)

* Big Mac Sauce

![big_mac_sauce.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bva2a4xic86pu8f8z08t.png)

* Ketchup

![ketchup.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ru622qkboroer7chtx6t.png)

* Mayonnaise

![mayonnaise.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xn32nvs8uj1ti30vcd7.png)

* Mustard

![mustard.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmedxm4pmqfvjg1jmxi5.png)

* Onions

![onions.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aysp2tjiw33nudlhaaal.png)

* Pickle Slices

![pickle_slices.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sr47jbszpkwljmzakstg.png)

* Shredded Lettuce

![shredded_lettuce.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/03ajyx1kwnlzor7kbldr.png)

### Burger

A simple class to store information about the burger: its price and a list of ingredients it contains. Also, class methods, such as *getFormattedIngredients()*, *getFormattedAllergens()* and *getFormattedPrice()*, returns these values in human-readable format.

![burger.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6w5h2trx4kio5s9t6l74.png)

### BurgerBuilderBase

An abstract class that stores *burger* and *price* properties defines some default methods to create/return the burger object and set its price. Also, the class defines several abstract methods which must be implemented by the derived burger builder classes.

![burger_builder_base.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t13lpm1f0mrirgopa1xw.png)

### Concrete builders

* *BigMacBuilder* — builds a Big Mac using the following ingredients: *BigMacBun*, *Cheese*, *BeefPatty*, *BigMacSauce*, *GrillSeasoning*, *Onions*, *PickleSlices* and *ShreddedLettuce*.

![big_mac_builder.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8rueoev2713qgnatwuxf.png)

* *CheeseburgerBuilder* — builds a cheeseburger using the following ingredients: *RegularBun*, *Cheese*, *BeefPatty*, *Ketchup*, *Mustard*, *GrillSeasoning*, *Onions* and *PickleSlices*.

![cheeseburger_builder.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1bnl8pfaj1dkj4ne47y.png)

* *HamburgerBuilder* — builds a cheeseburger using the following ingredients: *RegularBun*, *BeefPatty*, *Ketchup*, *Mustard*, *GrillSeasoning*, *Onions* and *PickleSlices*. *AddCheese()* method is not relevant for this builder, hence the implementation is not provided (skipped).

![hamburger_builder.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ur9zd65qkkdy8p2vngij.png)

* *McChickenBuilder* — builds a cheeseburger using the following ingredients: *RegularBun*, *McChickenPatty*, *Mayonnaise* and *ShreddedLettuce*. *AddCheese()* and *addSeasoning()* methods are not relevant for this builder, hence the implementation is not provided (skipped).

![mc_chicken_builder.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89zrsli1jxatngilvl8c.png)

### BurgerMaker

A director class that manages the burger’s build process and returns the build result. A specific implementation of the builder is injected into the class via the constructor.

![burger_maker.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2duo3p2qy8fxa798zycr.png)

### Example

First of all, a markdown file is prepared and provided as a pattern’s description:

![Builder Markdown](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/frveibk6wiui6r8vagj1.gif)

*BuilderExample* initialises and contains the *BurgerMaker* class object. Also, it contains a list of *BurgerMenuItem* objects/selection items which is used to select the specific builder using UI.

![builder_example.dart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ufjzekv4d40suxp1r8p.png)

The director class *BurgerMaker* does not care about the specific implementation of the builder — the specific implementation could be changed at run-time, hence providing a different result. Also, this kind of implementation allows easily adding a new builder (as long as it extends the *BurgerBuilderBase* class) to provide another different product’s representation without breaking the existing code.

![Builder Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aenha1l1htz3uo84j52g.gif)

As you can see in the example when a specific builder is selected from the dropdown list, a new product (burger) is created and its information is provided in the UI — price, ingredients and allergens.

All of the code changes for the Builder design pattern and its example implementation could be found [here](https://github.com/mkobuolys/flutter-design-patterns/pull/19).

## Your Contribution

💖 or 🦄 this article to show your support and motivate me to write better!
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.
📢 Share this article with your friends, colleagues on social media.
➕ Follow me on dev.to or any other social media platform.
⭐ Star the [Github](https://github.com/mkobuolys/flutter-design-patterns) repository.