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
itemsare not specified inRecipes. Itemis 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!