1- Strategy Pattern

Aside from formal definition, Strategy Pattern is widely used when you need to switch your algorithm or strategy in different places of your code.

Simple Example:

Suppose you build a game that has a Cat class that implements a Diet class. But let’s say your cat gained too much weight and now it needs to go on a diet that will help it lose weight for its health.

In this case, you can implement a Strategy Pattern such as:

interface EatBehavior public void eat();
>

diet types that implements the eat behavior

public class NormalDiet implements EatBehavior @Override 
public void eat() // normal food
>
>
public class LosingWeightDiet implements EatBehavior @Override
public void eat() // healthy food
>
>

cat class that HAS-A eat behavior

public abstract class Cat  EatBehavior eatBehavior; public Cat()<> 

public void eat() eatBehavior.eat();
>
>

And the client code would be like this:

cat.eat(); // Cat eats as usual.cat.setEatBehavior(new LosingWeightDiet());cat.eat(); // Cat eats with a healthier diet.

Strategy Patterns can also help you assign different behaviors for different subtypes.

Let’s say you have a spyhnx cat (a species of cat that doesn’t have any fur) and a tabby cat (or any other cat species that has a fur).

You can easily update your classes as follows:

interface EatBehavior public void eat();
>
interface DisplayBehavior public void display();
>

fur types that implements the display behavior

public class HasFur implements DisplayBehavior @Override 
public void display() // display with fur
>
>
public class NoFur implements DisplayBehavior @Override
public void display() // display without fur
>
>

a cat class that IS-A Cat type and HAS-A eat and display behavior

public class Sphynx extends Cat  EatBehavior eatBehavior; 
DisplayBehavior displayBehavior;
public Sphynx() eatBehavior = normalDiet();
displayBehavior = noFur();
>
public void eat() eatBehavior.eat();
>
public void display() displayBehavior.display();
>
>

another cat class that IS-A Cat type and HAS-A eat behavior with a different display behavior

public class Tabby extends Cat  
EatBehavior eatBehavior;
DisplayBehavior displayBehavior;
public Tabby() eatBehavior = normalDiet();
displayBehavior = hasFur();
>
public void eat() eatBehavior.eat();
>
public void display() displayBehavior.display();
>
>

And the client code would be like this:

Cat spyhnx = new Spyhnx();
sphynx.display(); // displays cat without fur
Cat tabby = new Tabby();
tabby.display(); // displays cat with fur

As seen above, it can also help you separate concerns of classes.

If one day you want to remove fur from the tabby for your game, you can just change how displayBehavior is set in the Tabby class and the client won’t need to be notified of this change.

Each class will only care of its own. (Single Responsibility Principle)

Real-Life Example:

Suppose you are writing a software that will show weather forecasts but you want to store the user information in a database and weather information in another database.

different database types that implements the database strategy

public class PostgreStrategy implements DatabaseStrategy @Override 
public void save() // save to PostgreSQL
>
>
public class CouchbaseStrategy implements DatabaseStrategy @Override
public void save() // save to Couchbase
>
>

The client code:

DatabaseContext db = new DatabaseContext();db.setDatabaseStrategy(new PostgreStrategy());
db.save(userInformation);
db.setDatabaseStrategy(new CouchbaseStrategy());
db.save(weatherInformation);

Again, if one day you want to change the way how PostgreStrategy or CouchbaseStrategy works, you won’t need to touch the client code.

In short, Strategy Pattern helps us to dynamically change the way our components work as we write code and separates our concerns.

To read it as a single story:
Strategy Pattern — A Quick Guide (3 min read)

2- Decorator Pattern

Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.”

Aside from formal definition, Decorator Pattern wraps around an object of a Decorator class, allowing you to dynamically change the behavior of an object at client code.

Simple Example:

Suppose you own a local pizza shop that has “have-it-your-way” style pizzas.

Its software has Pizza superclass with subclasses such as PizzaWithMushrooms, PizzaWithCorn, PizzaWithSalami, PizzaWithMushroomsAndCorn, PizzaWithMushroomsAndSalami, PizzaWithCornAndSalami, PizzaWithMushroomsAndCornAndSalami.

That’s not a very good practice, is it?

What if we want to add a new ingredient in the future? What if we want to add a new crust type, like Thin Crust Pizza? What if we want to update prices of each ingredient? What if we want to add x2 more corn?

In our case, this practice would result in a maintenance nightmare.

Our goal must be to allow our classes to add new behaviors, without modifying existing code. (Open-Closed Principle)

Written code should be reusable.

To achieve this, we can implement Decorator Pattern such as:

public interface Pizza String getSummary(); 
int getPrice();
>

pizza classes that implements the Pizza interface

public class StandardCrustPizza implements Pizza private static final String PRICE = 25; 

@Override
public String getSummary() return "Standard Pizza (" + PRICE + ")";
>
@Override
public int getPrice() return PRICE;
>
>
public class ThinCrustPizza implements Pizza private static final String PRICE = 30;

@Override
public String getSummary() return "Thin Crust Pizza (" + PRICE + ")";
>
@Override
public int getPrice() return PRICE;
>
>

pizza decorator abstract class that implements the Pizza interface

abstract class PizzaDecorator implements Pizza  @Override 
public abstract String getSummary();

@Override
public abstract int getPrice();
>

pizza ingredients that extends PizzaDecorator abstract class

public class Corn extends PizzaDecorator  
private Pizza pizza;
private static final String PRICE = 4;

Corn(Pizza pizza) this.pizza = pizza;
>
@Override
public String getSummary() return pizza.getSummary() +
", with corn (" + PRICE + ")";
>
@Override
public int getPrice() return pizza.getPrice() + PRICE;
>
>
public class Mushrooms extends PizzaDecorator private Pizza pizza;
private static final String PRICE = 6;
Mushrooms(Pizza pizza) this.pizza = pizza;
>
@Override
public String getSummary() return pizza.getSummary() +
", with mushrooms (" + PRICE + ")";
>
@Override
public int getPrice() return pizza.getPrice() + PRICE;
>
>
public class Salami extends PizzaDecorator
private Pizza pizza;
private static final String PRICE = 5;
Salami(Pizza pizza) this.pizza = pizza;
>
@Override
public String getSummary() return pizza.getSummary() +
", with salami (" + PRICE + ")";
>
@Override
public int getPrice() return pizza.getPrice() + PRICE;
>
>

And the client code would be like this:

Pizza pizza = new StandardPizza(); // standard pizza, base: 25
pizza = new Salami(pizza); // salami added, total: 30
pizza = new Corn(pizza); // corn added, total: 34
pizza = new Corn(pizza); // corn x2 added, total: 38
Output:
Standard Pizza (25), with salami (5), with corn (4), with corn (4)
Price: 38
Pizza pizza = new ThinCrustPizza(); // thin crust pizza, base: 30
pizza = new Mushroom(pizza); // mushroom added, total: 36
pizza = new Salami(pizza); // salami added, total: 41
Output:
Thin Crust Pizza (30), with mushroom (6), with salami (5)
Price: 41

See, it’s all very reusable! If one day you want to add a new crust/ingredient or update the prices of current ones, you won’t need to touch the client code.

Each class will only care of its own. (Single Responsibility Principle)

Real-Life Example:

Decorator Pattern is widely used in java.io package, such as:

InputStream in = new FileInputStream(file);
in = new BufferedInputStream(in );
in = new DataInputStream(in);

FileInputStream is the crust type here, while BufferedInputStream and DataInputStream are the ingredients.

You can even write your own decorator to your program by simply extending the java.io package decorators’ superclass (FilterInputStream) and wrap it around the base class FileInputStream.

public class UpperCaseInputStream extends FilterInputStream public UpperCaseInputStream(InputStream in) super(in); 
>
@Override
public int read() throws IOException return Character.toUpperCase(super.read());
>
>

And the client code would be like this:

InputStream in = new FileInputStream(file);
in = new UpperCaseInputStream(in);
// other decorators

In short, Decorator Pattern helps us to dynamically attach additional functionalities to our base class as we write code.

To read it as a single story:
Decorator Pattern — A Quick Guide (4 min read)

3- Observer Pattern

Observer Pattern defines one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

Aside from formal definition, Observer Pattern helps us to listen (subscribe) to a subject and be up-to-date whenever a change occurs.

Subjects are open for the Observers to subscribe, and does not know (nor care about) how they are implemented and vice versa.

Simple Example:

Suppose you are building a social media app and implementing it for multiple platforms.

a platform enum (for the sake of simplicity)

public enum Platform WEB(1), 
MOBILE(2);
>

a view interface that has a display method

public interface View void display();
>

a subject interface that has add/delete observer and notify observers methods

public interface Subject void registerObserver(Observer observer); 
void removeObserver(Observer observer);
void notifyObservers();
>

an observer interface that has an update method

public interface Observer void update(Double x, Double y);
>

Let’s say you want to show currency information in our app. Based on incoming data, you’ll update the numbers on the screen.

a currency class that implements the methods in Subject interface

public class CurrencyData implements Subject private final List observers = new ArrayList<>(); 
private Double value;
private Double interestRate;
@Override
public void registerObserver(Observer observer) observers.add(observer);
>
@Override
public void removeObserver(Observer observer) observers.remove(observer);
>
@Override
public void notifyObservers() observers.forEach(observer ->
observer.update(value, interestRate));
>
public void setValue(Double value) this.value = value;
notifyObservers();
>
public void setInterestRate(Double interestRate) this.interestRate = interestRate;
notifyObservers();
>
// getters>

Notice how notifyObservers() is called whenever a change occurs.

As your app grows larger, you may want to add new functionalities, such as weather information.

a weather class that implements the methods in Subject interface

public class WeatherData implements Subject private final List observers = new ArrayList<>(); 
private Double temperature;
private Double humidity;
@Override
public void registerObserver(Observer observer) observers.add(observer);
>
@Override
public void removeObserver(Observer observer) observers.remove(observer);
>
@Override
public void notifyObservers() observers.forEach(observer ->
observer.update(temperature, humidity));
>
public void setTemperature(Double temperature) this.temperature = temperature;
notifyObservers();
>
public void setHumidity(Double humidity) this.humidity = humidity;
notifyObservers();
>
// getters>

a currency display class that implements the methods in Observer and View interfaces

public class CurrencyDisplay implements Observer, View private Platform platform; 
private Double value;
private Double interestRate;
public CurrencyDisplay(Platform platform, Subject subject) this.platform = platform;
subject.registerObserver(this);
>
public void unsubscribe(Subject subject) subject.removeObserver(this);
>
@Override
public void update(Double temperature, Double humidity) this.value = temperature;
this.interestRate = humidity;
display();
>
@Override
public void display() // display
>
>

a weather display class that implements the methods in Observer and View interfaces

public class WeatherDisplay implements Observer, View private Platform platform; 
private Double temperature;
private Double humidity;
public WeatherDisplay(Platform platform, Subject subject) this.platform = platform;
subject.registerObserver(this);
>
public void unsubscribe(Subject subject) subject.removeObserver(this);
>
@Override
public void update(Double temperature, Double humidity) this.temperature = temperature;
this.humidity = humidity;
display();
>
@Override
public void display() // display
>
>

Let’s see it in action:

CurrencyData currency = new CurrencyData();
WeatherData weather = new WeatherData();
CurrencyDisplay webCurrency = new CurrencyDisplay(WEB, currency);
CurrencyDisplay mobileCurrency
= new CurrencyDisplay(MOBILE, currency);
// currency information is available for both platforms
WeatherDisplay mobileWeather = new WeatherDisplay(MOBILE, weather);
// weather information is available for mobile,
// not available for web
double temperature = 21.05;
weather.setTemperature(temperature);
// for weather -> only mobile is notified
double interestRate = 14.18;
currency.setInterestRate(interestRate);
// for currency -> both web and mobile got notified
mobileCurrency.unsubscribe(currency);
// for currency -> mobile is not listening anymore
interestRate = 15.20;
currency.setInterestRate(interestRate);
// for currency -> only web is notified

In Observer Pattern, the Subject is an open book. Observer is free to subscribe and unsubscribe based on its needs.

If you want to unsubscribe, it’s so easy! Since this design is loosely coupled, you can just call unsubscribe(subject) and it’s all done!

Loosely coupled designs allow us to build flexible object-oriented systems that can handle change. They minimize the interdependency between objects.

Real-Life Example:

Observer Pattern is widely used in javax.swing package.

Let’s think of a service that will update both the displays and the database information based on change of data:

UserData data = new UserData();Display webDisplay = new Display(WEB, data);
Display mobileDisplay = new Display(MOBILE, data);
Database postgresql = new Postgresql(data);
Database couchbase = new Couchbase(data);
// web display, mobile display, postgresql and couchbase
// all subscribed to user data.

Button is the subject here, when the button is clicked, data gets changed.

button.addActionListener((ActionListener) 
ae -> data.setEmail(email));

When data gets changed, all observers get notified and updated.

To read it as a single story:
Observer Pattern — A Quick Guide (4 min read)

4- Factory Pattern

“There are 3 types of Factory Pattern: Simple, Method and Abstract.”

Simple Factory

Suppose you have a local pizza shop and you instantiate a pizza object for every order you get.

Pizza pizza = new Pizza();

Instead of that, you can simply do this:

public class Pizza private Pizza()<> // hide the constructor, so no one 
initializes pizza with "new"
public static Pizza create() return new Pizza();
>
>
public class PizzaFactory public static Pizza create() return new Pizza(); 
>
>
public class Pizza
// assuming your models are in the same package, you can
make this package-private to make sure constructor won't be
called from client code
protected Pizza()<>
>

and the client code will be like this:

Pizza pizza = Pizza.create();orPizza pizza = PizzaFactory.create();

If you’d like to change how this method works (or maybe add some business logic to it), you can update create instead of putting the logic code to the constructor.

Don’t fret, I hear you, you say we could achieve the same thing with a constructor.
Well, Simple Factory is basically a constructor that has a custom name.

Think of it like this:

Person person = new Person(170);toPerson person = Person.fromHeight(170);orPerson person = PersonFactory.fromHeight(170);

It’s up to you to use it or not. I personally like it.

Some people don’t even count Simple Factory as a Design Pattern, though.
Factory Method and Abstract Factory on the other hand, is a bit different.

So let’s get to Factory Method.

Factory Method

So… back to the order management system.

Let’s say your business is larger now and you start to sell burgers.

Factory Method helps you to select between pizza and burger by overriding a method but keeps non-varying parts in a common method.

Let’s first create a Meal interface with meals implementing it.

public interface Meal // implementations
>
public class Pizza implements Meal // implementations
>
public class Burger implements Meal // implementations
>

Let’s make a more generic MealFactory interface with both PizzaFactory and BurgerFactory implementing it.

interface MealFactory //factory method 
Meal create(); // compulsory inheritance
>
public class PizzaFactory implements MealFactory // implementations @Override
Meal create() return new Pizza();
>
>
public class BurgerFactory implements MealFactory // implementations

@Override
Meal create() return new Burger();
>
>

Both pizza types override create according their own needs.

Now client code would be like:

MealFactory pizzaFactory = new PizzaFactory();
Meal pizza = pizzaFactory.create();
MealFactory burgerFactory = new BurgerFactory();
Meal burger = burgerFactory.create();

If both Meals have a common method regardless of their type, you can turn MealFactory to abstract class instead of an interface.

abstract class MealFactory //factory method 
protected abstact Meal create(); // compulsory inheritance
public void createAndSendOrder() Meal meal = create();
// do stuff
>
>
public class PizzaFactory extends MealFactory // implementations @Override
protected Meal create() return new Pizza();
>
>
public class BurgerFactory extends MealFactory // implementations

@Override
protected Meal create() return new Burger();
>
>

And the client code would be like:

MealFactory pizzaFactory = new PizzaFactory();
pizzaFactory.createAndSendOrder();
MealFactory burgerFactory = new BurgerFactory();
burgerFactory.createAndSendOrder();

It’s great because I also encapsulated the creation logic from client completely.

Abstract Factory

Now let’s add vegan options of pizza and burger.

So it will be like:

interface MealFactory Pizza createPizza(); // no inheritance needed 
Burger createBurger(); // no inheritance needed
>
public class VeganMealFactory implements MealFactory @Override
public Pizza createPizza() return new VeganPizza();
>
@Override
public Burger createBurger() return new VeganBurger();
>
>
public class NonVeganMealFactory implements MealFactory @Override
public Pizza createPizza() return new NonVeganPizza();
>
@Override
public Burger createBurger() return new NonVeganBurger();
>
>

Now it’s a factory of factories.

In Factory Method, only a single method was responsible of creation of a pizza, here we have separate methods for separate pizzas, so whole class is responsible.

In Factory Method,Pizza and Burger needed to be in type Meal,
here it’s not compulsory.

Let’s see the client code:

MealFactory veganMealFactory = new VeganMealFactory();
MealFactory nonVeganMealFactory = new NonVeganMealFactory();
Pizza veganPizza = veganMealFactory.createPizza();
Burger veganBurger = veganMealFactory.createBurger();
Pizza nonVeganPizza = nonVeganMealFactory.createPizza();
Burger nonVeganBurger = nonVeganMealFactory.createBurger();

Since both VeganMealFactory and NonVeganMealFactory are of type PizzaFactory, can’t we just decide between them using a simple decider?

public class MealFactoryDecider  private MealFactoryDecider()<> public static MealFactory decide(MealType mealType) switch (mealType) case VEGAN: 
return new VeganMealFactory();
case NONVEGAN:
return new NonVeganMealFactory();
default: throw new RuntimeException("Invalid type.");
>
>
>

And the final client code would be like:

MealFactory veganMealFactory =
MealFactoryDecider.decide(VEGAN);
MealFactory nonVeganMealFactory = MealFactoryDecider.decide(NONVEGAN);Pizza veganPizza = veganMealFactory.createPizza();
Burger veganBurger = veganMealFactory.createBurger();
Pizza nonVeganPizza = nonVeganMealFactory.createPizza();
Burger nonVeganBurger = nonVeganMealFactory.createBurger();

Remember to combine multiple patterns if you feel like it’ll be a good fit.

Wrap-Up

Simple Factory relies on readability: while it may not be considered a design pattern, it’s a simple way to decouple your clients from concrete classes.

Factory Method relies on inheritance: object creation is delegated to subclasses which implement the specific factory method to create objects.

Abstract Factory relies on composition: object creation is implemented in multiple methods exposed in the factory interface.

All factory patterns promote loose coupling by reducing the dependency of your application on concrete classes.

To read it as a single story:
Factory Pattern — A Quick Guide (4 min read)

5- Singleton Pattern

“Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.”

Simple Example:
Suppose you need a carpenter for a sofa, chairs and a cupboard.
It’d be the best if you call a one carpenter and do all the work with him.
It wouldn’t be wise to call a different carpenter for each object.

Real-Life Example:
It’s very similar to Simple Example. Let’s say you need a database client that you’ll handle all the CRUD operations.
You wouldn’t want to have multiple database clients since it will cause unexpected behaviors such as memory issues and data corruption.

Implementation

public class Singleton private static Singleton instance; 

private Singleton()<> // hiding the constructor

public static Singleton getInstance() if (instance == null) instance = new Singleton();
>
return instance;
>
// other methods
>

And the client code is:

Singleton singleton = Singleton.getInstance();

In the above implementation, the logic is such as:
if object does not exist → create and return object
if object exists → return already created object

Dealing with Multithreading

The problem with above code block is that in a multithreaded application objects might get initialized multiple times if threads access the same if block concurrently when getInstance() is used for the first time.

Let’s continue with possible solutions:

1. Eager Initialization

public class Singleton private static Singleton instance = new Singleton(); 

private Singleton()<> // hiding the constructor

public static Singleton getInstance() return instance;
>
// other methods
>

Using this approach, we pass the responsibility to JVM and it initializes our Singleton instance when the class is loaded, so multithreading is not an issue.

You can use this if you are sure you’ll use getInstance() at least one time in your application.

2. Locking the Initialization

public class Singleton private static Singleton instance; 

private Singleton()<> // hiding the constructor

public static synchronized Singleton getInstance() if (instance == null) instance = new Singleton();
>
return instance;
>
// other methods
>

We can lock the getInstance() by using synchronized keyword and force other threads to wait current thread to exit before entering this code block.

While the above example is correct (and used in most examples), this is a bad practice. We don’t need to lock the method every time getInstance() is called, we need to lock it the first time it’s being called. Since locking is a performance-wise expensive operation, we had better not lock whole method.

public class Singleton private static volatile Singleton instance; 

private Singleton()<> // hiding the constructor

public static Singleton getInstance() if (instance == null) synchronized(Singleton.class) instance = new Singleton();
>

>
return instance;
>
// other methods
>

Things to Consider

While Singleton Pattern is great and widely being used, it’s sometimes considered as an anti-pattern since it can help us mask bad design.

1. Violating loose-coupling
When we pass Singleton classes around like Singleton.getInstance(),
we may not realize the classes of our app know too much about each other, being too tightly-coupled.
For example passing the database client all over our app is a bad practice.

2. Violating Single Responsibility Principle
Singleton Pattern both handles ensuring a class has only one instance and providing an access point to it, which makes it carry two huge responsibilities on its shoulders.

3. Singleton Pattern vs Static Classes
We can make Singleton lazy-initialized with our if check above, static methods are lazy-initialized by default.
Singleton allows method overriding, static methods don’t allow overriding but can achieve similar behavior by method hiding.

When to use static class: If you are planning to write helper methods such as math, array manipulations etc., it can be easier to just use a class full of static helper methods.

When to use Singleton: Rest of everything. Singleton Class is just a normal class following normal OOP principles.

4. Singleton Pattern vs Dependency Injection
If you are already using a framework that handles injections, it may be a better practice to just inject classes instead of applying Singleton Pattern.

I prefer to first check if it’s a helper method, if yes, create a static class.
If not, check our DI availabilities. If yes, use DI. If not, use Singleton.

To read it as a single story:
Singleton Pattern — A Quick Guide (4 min read)

6- Builder Pattern

“Builder Pattern helps us construct complex objects by allowing creation of different representations of that object using same construction code.”

Builder Pattern is just a simple alternative of telescoping constructors and
many lines of setters.

public class Pizza  private int slices; 
private boolean cheese;
private boolean mushrooms;
public Pizza(int slices) < … >
public Pizza(int slices, boolean cheese) < … >
public Pizza(int slices, boolean cheese, boolean mushrooms) // implement methods>

So this is what a telescoping constructor look like.
We can extend it even more:

public Pizza(int slices, boolean cheese, boolean mushrooms, boolean pepperoni, boolean onions, boolean studentDiscount…)

Assuming slices is a required parameter and the rest of them is not,
it wouldn’t be wise to create a different constructor for each optional field to satisfy all object combinations.

Simplest way to get rid of this would be to just create a constructor which takes slice parameter and sets rest of the fields upon our needs.

public class Pizza private int slices; 
private boolean cheese;
private boolean mushrooms;
public Pizza(int slices) >

And the client code would be like:

Pizza pizza = new Pizza(2);pizza.setCheese(true);
pizza.setMushrooms(true);
pizza.setPepperoni(true);

This alternative doesn’t look good either.
The easiest way to save this code is to make a builder class, such as:

public class Pizza private int slices; 
private boolean cheese;
private boolean mushrooms;
private boolean pepperoni;
private boolean onions;
private boolean studentDiscount;
public Pizza(Builder builder) this.slices = builder.slices;
this.cheese = builder.cheese;
this.mushrooms = builder.mushrooms;
this.pepperoni = builder.pepperoni;
this.onions = builder.onions;
this.studentDiscount = builder.studentDiscount;
>
// getters & setterspublic static final class Builder private int slices;
private boolean cheese;
private boolean mushrooms;
private boolean pepperoni;
private boolean onions;
private boolean studentDiscount;
private Builder() <> public static Builder initialize(int slices) return new Builder().withSlices(slices);
>
public Builder withSlices(int slices) this.slices = slices;
return this;
>
public Builder withCheese() this.cheese = true;
return this;
>
public Builder withMushrooms() this.mushrooms = true;
return this;
>
public Builder withPepperoni() this.pepperoni = true;
return this;
>
public Builder withOnions() this.onions = true;
return this;
>
public Builder withStudentDiscount() this.studentDiscount = true;
return this;
>
public Pizza build() return new Pizza(this);
>
>
>

Since slices is a required field, Builder’s private constructor is hidden and has a simple factory method that only permits to initialize with slices.

Up until build() method is called, Builder returns a Builder type,
build()
method transforms Pizza.Builder to an actual Pizza object.

And the client code would be like:

Pizza pizza = Pizza.Builder 
.initialize(2)
.withCheese()
.withMushrooms()
.withStudentDiscount()
.build();

To read it as a single story:
Builder Pattern — A Quick Guide (2 min read)