Difficulty: Intermediate
What is the Factory design pattern? Implement a notification factory and explain the difference between Simple Factory, Factory Method, and Abstract Factory.
The Factory pattern is about separating the decision of which class to instantiate from the code that uses the object. Let me motivate it with a scenario you will meet in almost any project.
Your app needs to notify users by email, SMS, or push notification. Without a factory, every place that sends a notification has an if-else: if type is email, new EmailNotification(); else if type is sms, and so on. When you add WhatsApp, you have to hunt down and edit every one of those places. The creation logic is scattered, the caller is coupled to every concrete class, and violating the Open/Closed Principle is a matter of time.
A factory centralises that creation logic. The caller asks the factory for a Notification, passing a type, and receives something that implements the Notification interface. The caller only knows the interface, so adding a new notification type means changing the factory in one place, and the calling code stays untouched.
There are three related flavours, and interviewers like to check whether you know the distinction. The Simple Factory, sometimes not even counted as a formal pattern, is a single class with a static method containing the switch, as in the example. It is the easiest and most common in real projects. The Factory Method pattern, from the Gang of Four, defines an abstract creator class with a factory method that subclasses override to decide which product to create. For example, an abstract Dialog has createButton(), and WindowsDialog and MacDialog override it. The creation is deferred to subclasses through inheritance. The Abstract Factory pattern provides an interface for creating families of related objects without specifying their concrete classes: a UIFactory with createButton() and createCheckbox(), implemented by DarkThemeFactory and LightThemeFactory, guarantees that a button and a checkbox from the same family are always used together.
A quick way to remember: Simple Factory is one method with a switch, Factory Method is one product created through subclassing, and Abstract Factory is a family of products created through composition.
When should you use a factory? When object creation involves logic, when the exact type is decided at run time from configuration or input, when you want to hide complex construction, or when you want to return a cached or pooled instance. The JDK is full of examples: Calendar.getInstance(), NumberFormat.getInstance(), List.of(), and Executors.newFixedThreadPool() are all factory methods, as is Spring's BeanFactory.
Drawbacks: more classes, and a switch statement inside the factory still needs editing when a type is added, so the Simple Factory does not fully satisfy OCP. You can fix that by registering creators in a map at start-up, or letting a DI framework find implementations.
interface Notification { void notifyUser(String message); }
class EmailNotification implements Notification {
public void notifyUser(String m) { System.out.println("Email: " + m); }
}
class SmsNotification implements Notification {
public void notifyUser(String m) { System.out.println("SMS: " + m); }
}
class PushNotification implements Notification {
public void notifyUser(String m) { System.out.println("Push: " + m); }
}
class NotificationFactory {
static Notification create(String type) {
return switch (type.toLowerCase()) {
case "email" -> new EmailNotification();
case "sms" -> new SmsNotification();
case "push" -> new PushNotification();
default -> throw new IllegalArgumentException("Unknown type: " + type);
};
}
}
public class FactoryDemo {
public static void main(String[] args) {
NotificationFactory.create("sms").notifyUser("Your order shipped");
NotificationFactory.create("EMAIL").notifyUser("Invoice attached");
try {
NotificationFactory.create("fax");
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}
factory, design-patterns, creational, polymorphism