Factory Pattern: Producing Objects, Pooling Resources
Welcome to the factory, oh, I mean, the Factory Design Pattern blog post. Here we will see how we can produce subjects and reuse existing objects. Let's power up the machine and start producing objects.
What is Factory Design Pattern?
The Factory Design Pattern is a creational pattern that allows us to create objects of classes without actually touching them. With this pattern, we can create objects without directly initialising the specific class or calling its constructor. We can use an interface or abstract class to create objects and hide concrete implementation details.
Benefits:
There are several benefits that we get if we implement factory design pattern in our code. Below are some of them.
We can make our code more readable.
If we need to create several objects regularly, we can implement this pattern to centralise the object creation part at one place.
It will become easy to maintain our code.
We can de-couple the logic of object creation from the code that is trying to use that object.
We can easily create different objects based on client input without actually changing client code.
These were some of the benefits I remembered. If you think I am missing something, please comment on it.
Real Life Scenario
Let's keep it simple and suppose you are developing an application and you can send notifications to users via three channels.
1. Email
2. Push
3. InApp
In your codebase, there are more than a hundred places where you are sending notifications by creating an object of each type of notification class. At those hundred places, you are directly interacting with concrete implementations of notification classes, and if any functionality changes in any class, you will have to handle it in all those hundred places.
But what if we introduce a notification factory between the caller and the notification class? Won't that make your life simple? Absolutely it will now; you need to interact with that notification factory, and it will handle object creation logic for you.
In case the creation logic changes in any of the concrete notification classes, then you just need to handle it in the notification factory.
Implementation
Let's start by creating a notification interface and two classes that will implement that interface.
Now we have a factory that will ask us for the type of notification that we want to send. It will then return an object of that specific notification type class, and we can use the send method that we declared in the interface and implemented in our class.
Finally in our main method we can bring up all these things together.
What About Resources?
In the above implementation, the objects that we are creating are basic and don't require that many resources from our system. That's why if we create too many objects, it won't cause an issue.
But in scenarios where objects require high resources, it will degrade system performance.
For example, there are 1000 Go routines running in your application in the background, and those are sending emails by creating their own objects. Which means that we are creating 1000 objects. But all of this can be achieved with just a single object also. Then why waste system resources?
To solve this problem, we will use pooling.
What is Resource Pooling?
Resource polling is a concept in which we can reuse the resources. In our context, we will reuse objects of notification classes instead of creating new ones every time. So we will implement a pool in which we can store our objects and reuse them without creating new ones again.
This is how this process will look:
Create an object of notification class.
Put it in pool.
Next time get it from pool and don’t create new.
We will use Golang sync.Pool for implementing this resource pool as it is thread safe also, so we do not need to worry about concurrency.
sync.Pool provides us with the functions Get() and Put(). When the Get function is called, it will check if there is one instance of the object available in the pool. If it is available, it will return that existing object; in case it is not available, then it will create a new object.
Thereafter, we can call the Put() method to put that object in the pool. After this two-step process, whenever we call the Get() method, the existing object will be returned.
While creating a thread pool, we have to satisfy an argument: New: That asks for a function that will be executed every time the Get() function is called and a new object needs to be created.
In our scenario, we have 2 pools: one will store an object of emails, and another will store an object of the push class. That new method will be responsible for creating new objects for the appropriate class in case they are not available in the pool.
We have implemented a wrapper function over the Get() and Put() functions of the pool because we have to query the pool based on the notification type that the code is asking for.
Finally, we have our main function that will bind all these things together.
Source Code:
Basic Implementation: https://github.com/x-sushant-x/02-FactoryPattern
Object Pooling: https://github.com/x-sushant-x/02-FactoryPattern/tree/object-pooling
Also Read
Subscribe Its FREE!!
I keep posting things that I learn on this blog. You can subscribe to my newsletter and I will make sure that you will receive every post In your mailbox. It is completely free.
More Design Pattern?
Thank You
Thank you for reading my blog, and if you have any suggestions related to the above implementation or anything else, you can comment them down. Any improvements will be highly appreciated. Thank you, and have a nice day.