Design Patterns in Golang- Factory
In our previous blog, we learned that in the Builder pattern, we create an object (struct instance) piece by piece.
As a developer, you get into situations where you want to create the whole object at once. In these situations, you can apply the Factory pattern.
“ Factory pattern is a software design pattern where we create the whole instance at once”
When to use this?
It is used when the creation of an object becomes complex.
What do you mean by “complex”?
- When an object has a lot of properties to be filled properly.
- Scenarios where a lot of properties carry default value.
How can we implement a Factory pattern?
There are 4 ways to implement a Factory pattern.
- Factory function
- Interface Factory
- Factory Generator
- Prototype Factory
Factory Function
From this example, it is clear that the “factory function” is a constructor.
Quick explanation:
Since we would be creating Person
objects for “girls hostel” it is better to create a factory function NewGirl()
which can create person
objects with pre-populated gender
value.
Interface Factory
Instead of returning an object (instance of a struct), we can return an interface that complies with the object.
This is really familiar to us in our day to day work.
See this example:
- Imagine a scenario where we need to create an interest calculator
- Based on the “type” we create a calculator instance with different underlying behaviour.
- In the above example, based on the type, the
NewCalculator()
factory function returns asimpleInterest
orcompoundInterest
instance and their underlying logic changes in their respectiveCalculate()
function.
Factory Generator
As the name suggests this is used to generate “factories”.
For example, we want to create factories for employees based on roles.
In functional approach line 12-29
:
- We create separate factories based on roles and then we can create instances using those factories. ( “churning out developers from
developerFactory
”) - Notice that the factory itself is of the type
func
so that it can be passed to other functions, which is essentially the base of functional programming. - Since the factory is type
func
, it can be consumed easily by other functions. - In this approach is that the factory itself cannot mutate an object. e.g.
developerFactory.AnnualSalary = 100
is illegal.
In structural approach 31-50
:
- We create a separate factory struct
EmployeeFactory
. - We create a constructor of
EmployeeFactory
. - We define a
Create()
as a member ofEmployeeFactory
that returns anEmployee
object. - The Advantage of this approach is the factory can mutate the object.
e.g.bossFactory.AnnualIncome = 500
is legal. - Since
EmployeeFactory
is a special type unlikedeveloperFactory (line:20)
the end-user consuming this type should know what function/s (Create
in this case ) are exposed. This can be done using interfaces.
We will discuss the Prototype Factory pattern when we dive into the Prototype pattern.
In conclusion, a factory pattern is a combination of some glorified constructors who can help in the wholesale construction of an object. (Oversimplified).