Factory Pattern: Centralizing Object Creation for Cleaner Code
When you're building a scalable system, how you create objects matters just as much as what they do.
Let’s look at a simple requirement:
💬 “Send a notification to the user — via SMS, Email, or Push.”
A junior developer might start like this:
Notification notification = new SMSNotification();
notification.notifyUser();
This works for now… but over time, this approach creates 5 major problems:
❌ Problems Without Factory Pattern
✅ Solution: Factory Pattern
Let’s apply the Factory Pattern to solve all these issues step-by-step.
🧱 Step 1: Define the common interface
public interface Notification {
void notifyUser();
}
🧱 Step 2: Concrete implementations
public class SMSNotification implements Notification {
public void notifyUser() {
System.out.println("Sending SMS notification");
}
}
public class EmailNotification implements Notification {
public void notifyUser() {
System.out.println("Sending Email notification");
}
}
public class PushNotification implements Notification {
public void notifyUser() {
System.out.println("Sending Push notification");
}
}
🧱 Step 3: Create the Factory
public class NotificationFactory {
public static Notification createNotification(String channel) {
if (channel == null || channel.isEmpty()) {
throw new IllegalArgumentException("Channel must not be null or empty");
}
switch (channel.toUpperCase()) {
case "SMS":
return new SMSNotification();
case "EMAIL":
return new EmailNotification();
case "PUSH":
return new PushNotification();
default:
throw new IllegalArgumentException("Unknown channel: " + channel);
}
}
}
🧱 Step 4: Client code becomes super simple
public class NotificationService {
public static void main(String[] args) {
// Simulate dynamic channel source, e.g., from config or DB
String userPreferredChannel = "EMAIL";
Notification notification = NotificationFactory.createNotification(userPreferredChannel);
notification.notifyUser();
}
}
✅ How Factory Pattern Solves Our Problems
Recommended by LinkedIn
🚀 Real-World Use Case
Let’s say tomorrow the product team wants to add Slack Notification.
✅ You only need to:
case "SLACK":
return new SlackNotification();
No changes to any other part of the system. That’s powerfully scalable.
🧠 Real-Life Analogy
Imagine you’re ordering from a food delivery app.
You don’t care how food is cooked — you just select “Pizza” or “Burger” and the system delivers it.
The app is like your client code.
The kitchen (factory) decides which chef (class) prepares your order.
✅ Key Benefits Recap
💬 Final Thought
If you're writing new all over your services, you're silently scattering responsibility and tightly coupling your code.
Use a Factory to cleanly encapsulate creation logic — your future self (and your team) will thank you.