This is one of the most used patterns. Let’s jump right into it.
Problem:
Let’s consider a real world example. In one of the sprint planning meeting, your PM comes in with a request. The client has requested a feature, where on checkout the app can send notifications to the user. The notification involves the summary of their order along with the shipping information. For our given use case let’s not worry about the information that goes in the notification. We can assume that there is an API which will help us populate this information.
Client wants notification via email for now. The task gets assigned to you. Its’ pretty straightforward if you think about it. You start by creating a class EmailNotification.
We have kept it very simple for obvious reasons. Now, we can use this class in the checkout page. As soon as the user checks out his/her order we can instantiate EmailNotification class and use send_notification() method to send an email to the user.
For completeness, you wrote the documentation on how to use this class. Your team members working on checkout page can now use this class and hook it up with the checkout button.
This works well for now. It’s very easy to understand and also maintains the single responsibility principle. This goes into the production and everyone is happy about it.
The client is so impressed by this feature that they request for a new form of notification. They now prefers to receive notifications by SMS. Now of course the PM comes to you with this new request.
There are two ways to handle this new feature request. First, you can create a new class for SMS notification. Second, you can change the existing EmailNotification class. Modifying the existing class is not a good idea as that would violate the Open-Closed principle. The principle states that the classes should be open for extension and closed for modification.
Creating a new class now seems like the only solution we have. So we go ahead and put in place a new class SMSNotification.
Although this works, I see a problem here.
The checkout page has to handle object creation and also decide whether the user wants Email Notification or SMS Notification.
The checkout page does not follow single responsibility principle here. Let’s see how we can leverage Factory Design Pattern to solve this.
Factory Design Pattern:
Factory design pattern uses factory methods to deal with the problem of creating objects. So, the client (in this case, the checkout page) does not have to take on the responsibility of creating objects.
In above example we can refactor our code a bit. Let’s create a new class NotificationFactory.
The checkout page has to specify what kind of notification it needs while instantiating NotificationFactory. Factory will take care of initializing the object.
In review this solves our problem stated above.
This was a simple example that might help you to implement much more complex designs.
When to use it:
When you want to outsource the logic of initializing objects if they depend on conditions. Deciding which class to initialize adds more responsibility which is not desirable.
When not to use it:
You should default to not using factories. Factories are only necessary when you need to abstract away object creation. Adding more classes always adds to the complexity. Only add complexity when necessary.