Highlight - The Builder Pattern
A creational design pattern created to decouple details into a friendly API for constructing an object.
Builder Design pattern
The builder design pattern focuses on specifying parts for the object and finally constrcuting it.
This allows a “Full” construction or Partial construction.
Diagram and Usage
IBuilder
constructs abstractions based on parts added by construction methods
- AddPartA()
and AddPartB()
.
Finally Construct
returns a concrete object of IObject
.
A good addition to the pattern is returning the same object on construction so the API
can be chained.
Example:Builder.AddPart("one").AddPart("two").Build();
C# Example of the diagram
1 | public interface IObject { } |
Example 1: Alchemy crafting
I like to use fantasy like examples for systems because it shows how creative you can get with these patterns.
Recipe | Result |
---|---|
Leaves + Claws | Swiftness |
Fire + Bricks | Fire bricks |
Fire + Metal | Hard Metal |
We need an ingredient:
1 | public class Ingredient |
Now we need a recipe:
1 | public class Recipe |
Let’s assume that our game engine contains an Item which is also an Ingredient:
1 | public class Item : Ingredient |
Now we need an alchemy engine:
1 | public interface IAlchemyCraft |
Now we can craft the alchemy crafting system based on recipes:
1 | public class AlchemyRecipeCrafts : IAlchemyCraft |
AlchemyRecipeCrafts
contains a list of current ingredients which are cleared when we combine them.
We need to create the recipes for the defined items.Swiftness
, Fire Brick
and Hard Metal
.
Usage:
1 | AlchemyRecipeCrafts crafting = new AlchemyRecipeCrafts(); |
In this manner we can construct items dynamically.
This specific system lacks few things:
- Amount of
items
are not specified inRecipes
. Item
is a static class - to make it more generic we should construct item classes not by specific classes but by the generic class.
For example:new Item() { Name="Claws", Type = ItemType.Ingredient };
Of course it depends on the game engine.- Configuring the recipes (For example with json) to create items.
Example 2: Abstracting SQL as a builder:
One of my favorite examples for this pattern is constructing SQL statements.
The system contains a table of people, this is the class:
1 | public readonly record struct Person(string Name, int Age); |
The statement builder:
1 | public interface IStatementBuilder<T> |
Usage:
1 | IPersonFetcher fetcher = new PersonFetcher(); |
The SQL
built may look like so:
1 | SELECT * FROM People |
Alternatives
The builder design pattern allows to construct an item from many ingredients.
If we don’t need that kind of behavior we may use the alternatives:
Factory
- Abstract away the creation process.Prototype
- Clones an object.Singelton
- Creates a single instance.
In the Alchemy
example we actually used a factory lambda.
The Func<Item>
is a factory for items using a lambda.
The Factory
pattern is more common than the Builder
pattern,
Yet I prefer the Builder
for constructing more complex objects.
The SQL
example is very pracical and as you can see it simplifies the usage of statement construction.
Thanks for reading!