Design patterns in Golang — The Builder
I always wondered, how should we apply our very dear “Design Patterns” in Golang?
Object-Oriented Programming in Go is weird. If you are a Java or a C# developer, you would find a lot of similarities in applying SOLID principles in your code. But Go is special and special for a reason.
We would be taking a closer look at how we can implement some famous design patterns in Go.
The motivation behind the Builder pattern is to create a complex object piece-by-piece. Our goal in this blog is to provide APIs to create complex objects step-by-step.
Some objects are easy to create with a simple constructor while others need a lot of ceremonies.
When do we need this?
When you don’t need your end-user to provide millions of details in parameters of a constructor and you want to make his/her life easy by providing them with a simple way to create a complex object.
- Builder facets
- Builder parameters
- Functional builders
They are more than one builder working in tandem to create an object.
Sometimes, our object is complex and the creational process requires more than one builder class. Segregating the builder into multiple builders also gives us control over the properties of a struct that a user can use.
Show me the code!
Suppose we want to create a fluent API that builds a person object like this:
We start with creating a
Person struct and 3 builders
Notice that the
Next, we would declare the constructors for these builders.
Notice how Lives() and Works() refer to PersonBuilder while initalization
Now, why this is important?
This would enable us to set properties of
Person which is part of
Ok, how would we set properties now?
Glad you asked!
We would create some behaviours/functions/methods for
PersonJobBuilder that sets the properties of the
and finally, a “Build” method that returns a
So, putting it all together!
Once an object of
PersonBuilder is created we switch to
Lives() that returns a
PersonAddressBuilder which have member functions like
WithPostalCode() , since we are returning pointers in all the function definitions we can chain our function calls together (line 91–97)
This way we can jump between different builders and use their corresponding member functions to create a complex object.
The result (trivial) looks like this:
Builder Parameters: https://devcharmander.medium.com/go-builder-pattern-builder-parameters-637cd3f46240
Functional Builders: https://medium.com/@devcharmander/go-builder-pattern-the-functional-way-e40f347017ce