Factory Method Design Pattern in Java
Learn how the Factory Method design pattern creates objects without tightly coupling your Java code to concrete classes.
What is the Factory Method pattern?
The Factory Method pattern creates objects without exposing the exact object creation logic to the client.
Instead of using the new keyword directly, the client asks a factory to create the required object. This keeps business logic independent from concrete implementations.
When to Use Factory Method
Use Factory Method when:
- Object type depends on user input.
- Multiple implementations of an interface exist.
- Object creation logic may change.
- The client should not know the concrete implementation.
- Runtime decisions determine which object to create.
Advantages of Factory Method
- Hides object creation logic.
- Reduces coupling.
- Supports multiple implementations.
- Makes the code easier to extend.
- Centralizes object creation.
Disadvantages of Factory Method
- Adds additional classes.
- Factory logic may become large.
- Too many conditions can reduce maintainability.
Real-World Examples
- Creating payment processors.
- Selecting notification channels.
- Creating file parsers.
- Choosing database drivers.
- Creating objects based on input.
The problem it solves
Imagine an order system that creates different notification types. If every service directly creates EmailNotification, SmsNotification, and PushNotification, the business code becomes coupled to every concrete class.
When a new notification type is added, many classes may need changes. Factory Method gives the creation decision one clear home.
Simple idea: ask for a product by its common type, and let a factory decide which concrete implementation to create.
Beginner-friendly Java example
Step 1: Define the product contract
All notification types implement the same interface. This allows the rest of the application to work with Notification instead of a specific class.
public interface Notification {
void send(String message);
}Step 2: Create concrete products
public class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Email: " + message);
}
}
public class SmsNotification implements Notification {
public void send(String message) {
System.out.println("SMS: " + message);
}
}Step 3: Create the factory method
The factory hides the new operation and returns the shared product type.
public final class NotificationFactory {
private NotificationFactory() { }
public static Notification create(String channel) {
return switch (channel.toLowerCase()) {
case "email" -> new EmailNotification();
case "sms" -> new SmsNotification();
default -> throw new IllegalArgumentException(
"Unsupported channel: " + channel);
};
}
}Step 4: Use the factory
Notification notification =
NotificationFactory.create("email");
notification.send("Your order was shipped");Benefits and trade-offs
- Centralizes object creation.
- Reduces coupling to concrete classes.
- Makes new product types easier to add.
- Improves testing through common interfaces.
- Introduces additional classes or methods.
- The factory can become large if it handles too many products.
- Invalid input needs clear validation.
When should you use Factory Method?
- Object creation depends on input, configuration, or environment.
- Several classes share a common interface.
- You expect new product implementations over time.
- You want business logic to avoid direct constructor calls.
