A creational design pattern created to decouple details into a friendly API for constructing an object.
The builder design pattern focuses on specifying parts for the object and finally constrcuting it.
This allows a “Full” construction or Partial construction.
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();
1 | public interface IObject { } |
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:
items
are not specified in Recipes
. Item
is a static class - to make it more generic we should construct item classes not by specific classes but by the generic class.new Item() { Name="Claws", Type = ItemType.Ingredient };
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 |
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!