Design Patterns - Factory Pattern
The factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.
The series was off last week, so there's two posts to compensate. This week we will be going through the factory pattern and the singleton pattern. If you haven't checked out the other posts in the series I highly recommend you do.
The factory pattern isn't a design pattern as much as it is a part and parcel of the Java ecosystem. Let's have a look at the textbook definition from Wikipedia
In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.
Now that's a mouthful, so let's break it down piece by piece. The factory pattern is a creational pattern. So far we have seen several design patterns but those primarily deal with the organizational aspect of programming. The factory pattern primarily deals with the creation and instantiation of objects hence it's a creational design pattern.
A problem we have not yet dealt with in the previous posts in the series was the usage of new
keyword. Despite trying to avoid concrete implementations, we were still instantiating a lot of them. The factor pattern aims to allay some of these concerns.
Finally, the last part of the definition talks about how we avoid burderning the constructor with a menagerie of optional configurations and instead creating a dedicated function for managing instantiation of the class based on certain parameters. But still it's probably hard to understand this from pure words, let's look at the actual code to understand this.
Traditional Approach
As has been customary throughout this series at this point, let's take an example that has to with cars.
Our CarDealer
class here has a sellCar method that first creates a car variable and then has a lengthy if else statement to manage the creation of the specific brand of the car. Now this results in some problems for us.
- What if the dealer starts selling a new kind of car, perhaps a car by
Waymo
, each change would require us to modify thesellCar
function and ensure it stays upto date. Similarly, any removals would require us to remove the particular statment. - In addition,
sellCar
may not be the only function that requires creation of objects, perhaps there's another functiondesignCar
that requires the same object creation process. We will be dealing with a lot of duplicate code, any modifications would need to be replicated across the codebase.
So how do we deal with this? Enter the humble Factory.
Factory Approach
We need to identify the part of the code that is repetitive and can function independently.
As we can see, this is the part of the code that deals exclusively with the creation of the object. We can create a new factory class called CarFactory
.
And now we can just have the CarDealer
class become a client of the CarFactory
class for the generation of objects. We can add new car creation statements and remove or modify existing ones to this new class. Any changes we do in this single entity would reflect across any classes which are powered by this factory and we do not need to manually update every class. This fits right in with the Single Responsibility principle that we talked about in the Decorator Pattern post.
In this new and updated version of the CarDealer
class we have created a private member variable factory
which is an instance of the CarFactory
class. This allows us even more flexibility to switch the factories in the future if we ever need to. The instantiation car is dealt entirely by the factory and the sellCar
method can continue to focus on the actual function it was designed for.
Closing Thoughts
As I mentioned before - there's two posts this week, make sure to check out the post detailing how to go about implementing the Singleton Pattern as well!
As always I would love to hear your feedback on this post, feel free to write to me at akshay [at] akshayprabhu [dot] dev or tweet at my twitter handle @akshaprabhu200.