Build objects in a readable way
Object Oriented Programing (OOP) languages are all about design, creating and manipulating objects. Object are instances of classes.
The first things when teaching a OOP language is how to design and create classes. Like the following:
public class Car {
public string Name { get; set; }
public string Color { get; set; }
public Engine Engine { get; set;}
...
public Car(string name, string Color, Engine engine) {
Name = name;
Color = color;
Engine = engine;
}
}
In this example, we have a Car that has one Engine. When creating an instance, one usually does the following:
var engine = new Engine(...)
var car = new Car("Mercedes SLK", "Black", engine);
The code above is totally fine and works, however in terms of releaving intent and exposing how the class Car is built the doesn't know unless it opens the class Car.
Builder to the rescue
One way to improve the previous object initialization is:
public class CarBuilder {
private Engine engine;
private string name;
public CarBuilder WithName(string name) {
this.name = name;
return this;
}
public CarBuilder WithEngine(Engine engine) {
this.engine = engine;
return this;
}
public Car Build() {
return new Car(name, color, engine)
}
}
...
{
var car = new CarBuilder()
.WithName("Mercedes SLK")
.WithColor("Black")
.WithEngine(new Engine(...))
.Build();
}
With this example we know that this car, has a name, color and an engine (just by reading the code.
Ok.. we can still improve this concept by adding a new helper class (some more sintatic sugar).
public static class A {
public static Car Car => new CarBuilder();
}
...
{
var car = A.Car
.WithName("Mercedes SLK")
.WithColor("Black")
.WithEngine(new Engine(...))
.Build();
}
This is a simple thing, that helps increasing code reability.
When to use
Currently, I apply this pattern when doing tests. Why? Because it helps a lot when building the initial state of objects for tests. When the next person reads the test knows exactly how the objects are being initialized. Furthermore, this is also helps you understand the relationship between a classe and it's dependencies.
Another case to apply this is when dealing with edge cases, like the follwoing:
public static class A {
//assuming that this can happen :)
public static Car CarWithNoEngine => new CarBuilder().WithName("No Engine Car").Build();
}
Conclusion
The point of applying this is pattern is to promote readability for the future you (that will mainting the code) or for a fellow colague.
Thank you and Happy coding.