Design Pattern Course
The Factory Design Pattern is a creational design pattern that hides object creation logic and returns objects through a common abstraction. Instead of creating objects directly with new, client code asks a factory for the required object and works with an interface or abstract class.
This improves loose coupling, keeps creation logic in one place, and makes the code easier to maintain and extend.
Why Factory Pattern is useful
In real applications, the exact object type often depends on runtime input, configuration, or environment. If client code creates concrete classes directly, the code becomes tightly coupled and harder to change.
Factory Pattern solves this by centralizing object creation and exposing only the abstraction to the client. That means the client does not need to know which class is being instantiated.
Types of factory patterns
There are three common factory-related patterns:
- Simple Factory: a single factory class or method returns different objects based on input.
- Factory Method: subclasses decide which object to create.
- Abstract Factory: creates families of related objects without specifying their concrete classes.
A simple factory is not one of the original GoF design patterns, but it is widely used in Java and often serves as the easiest introduction to the factory concept.
Simple Factory example
Abstraction
public interface NotificationExecutor { void executeNotification(); }
Concrete implementations
public class EmailNotificationExecutor implements NotificationExecutor { @Override public void executeNotification() { System.out.println("Email notification sent"); } }
public class SMSNotificationExecutor implements NotificationExecutor { @Override public void executeNotification() { System.out.println("SMS notification sent"); } }
public class UnsupportedNotificationExecutor implements NotificationExecutor { private final String type; public UnsupportedNotificationExecutor(String type) { this.type = type; } @Override public void executeNotification() { System.out.println("Notification implementation not defined for " + type); } }
Factory class
public final class NotificationExecutorFactory { private NotificationExecutorFactory() { } public static NotificationExecutor getNotificationExecutor(String type) { if (type == null) { return new UnsupportedNotificationExecutor("null"); } switch (type.toLowerCase()) { case "email": return new EmailNotificationExecutor(); case "sms": return new SMSNotificationExecutor(); default: return new UnsupportedNotificationExecutor(type); } } }
Usage
public class NotificationSender { public static void main(String[] args) { NotificationExecutorFactory.getNotificationExecutor("Email").executeNotification(); NotificationExecutorFactory.getNotificationExecutor("SMS").executeNotification(); NotificationExecutorFactory.getNotificationExecutor("FTP").executeNotification(); } }
Output
Email notification sent SMS notification sent Notification implementation not defined for FTP
Advantages
- Reduces coupling between client code and concrete classes.
- Centralizes object creation logic.
- Improves readability and maintainability.
- Makes it easier to add validation, logging, caching, or pooling later.
Limitations
- A large switch or if-else chain can become hard to maintain.
- Adding new types may require changes in the factory.
- It can introduce extra classes and indirection.
- It should not be used if object creation is already simple and unlikely to change.
Factory Method vs Abstract Factory
Factory Method is used when subclasses decide which class to instantiate. Abstract Factory is used when you need to create related families of objects together, such as light and dark UI themes or different database-specific DAO components.
Best practices
- Prefer enums or a registry over raw strings.
- Keep factories focused only on object creation.
- Use private constructors for utility-style factory classes.
- Use dependency injection when object wiring becomes complex.
- Use thread-safe collections if the factory stores shared mutable state.
JDK examples
Common examples of factory-style APIs in Java include:
Calendar.getInstance()NumberFormat.getInstance()DriverManager.getConnection(...)
These methods return suitable implementations without exposing the concrete class directly.
Interview takeaway
A good one-line answer is:
Factory Design Pattern encapsulates object creation and returns objects through a common interface, reducing coupling between client code and concrete implementations.