Introduction
In software development, creating objects can become complicated when a program needs to work with different types of objects. If object creation logic is written directly throughout the application, the code can become tightly coupled and difficult to maintain.
The Factory Method Design Pattern provides a solution to this problem. It is a creational design pattern that defines a method for creating objects while allowing subclasses to decide which specific object should be created.
Instead of directly creating an object using the new keyword everywhere, the Factory Method delegates the responsibility of object creation to a separate method.
What is the Factory Method Pattern?
The Factory Method Pattern is a design pattern in which a superclass defines a method for creating an object, but the subclass determines the actual type of object that will be created.
The main idea can be expressed as:
Let subclasses decide which object to create.
For example, imagine a notification system that can send:
- Email notifications
- SMS notifications
- Push notifications
Without a Factory Method, the application may contain many if-else or switch statements for deciding which notification object to create.
With the Factory Method, the object creation process is separated from the code that uses the object.
The Problem Without Factory Method
Consider a simple notification application.
class EmailNotification {
void send() {
System.out.println("Sending Email");
}
}
class SMSNotification {
void send() {
System.out.println("Sending SMS");
}
}
Suppose the application directly creates objects:
public class NotificationService {
public void sendNotification(String type) {
if (type.equals("email")) {
EmailNotification email = new EmailNotification();
email.send();
} else if (type.equals("sms")) {
SMSNotification sms = new SMSNotification();
sms.send();
}
}
}
This approach works, but there is a problem.
If we later add:
WhatsAppNotification
PushNotification
TelegramNotification
the NotificationService class must be modified every time.
This creates tight coupling between the service and the concrete notification classes.
Solution Using Factory Method
The Factory Method solves this problem by introducing a common interface.
Step 1: Create the Product Interface
interface Notification {
void send();
}
This represents the common behavior of all notifications.
Step 2: Create Concrete Products
class EmailNotification implements Notification {
public void send() {
System.out.println("Sending Email");
}
}
class SMSNotification implements Notification {
public void send() {
System.out.println("Sending SMS");
}
}
Both classes implement the Notification interface.
Step 3: Create the Creator
abstract class NotificationCreator {
abstract Notification createNotification();
public void sendNotification() {
Notification notification = createNotification();
notification.send();
}
}
The createNotification() method is the Factory Method.
The creator does not know which concrete notification will be created.
Step 4: Create Concrete Creators
class EmailNotificationCreator extends NotificationCreator {
@Override
Notification createNotification() {
return new EmailNotification();
}
}
class SMSNotificationCreator extends NotificationCreator {
@Override
Notification createNotification() {
return new SMSNotification();
}
}
Each subclass decides which object should be created.
Step 5: Use the Factory Method
public class Main {
public static void main(String[] args) {
NotificationCreator creator;
creator = new EmailNotificationCreator();
creator.sendNotification();
creator = new SMSNotificationCreator();
creator.sendNotification();
}
}
Output
Sending Email
Sending SMS
How Does Factory Method Work?
The pattern can be understood through four main components:
Creator
|
createNotification()
|
----------------
| |
EmailCreator SMSCreator
| |
↓ ↓
EmailNotification SMSNotification
1. Product
Defines the common interface for the objects.
Example:
interface Notification
2. Concrete Product
Implements the product interface.
Examples:
EmailNotification
SMSNotification
3. Creator
Declares the Factory Method.
Example:
abstract class NotificationCreator
4. Concrete Creator
Overrides the Factory Method and decides which concrete product to create.
Examples:
EmailNotificationCreator
SMSNotificationCreator
Real-World Example
Consider an online food delivery application.
The application may support different payment methods:
Payment
|
├── CreditCardPayment
├── UPIPayment
└── CashPayment
Instead of making the main application directly create each payment object, the Factory Method can delegate object creation to specialized creators.
This makes it easier to add another payment method later without heavily modifying existing code.
For example:
UPI
Credit Card
Debit Card
Cash
Digital Wallet
The same concept can be used in:
- Database connection creation
- Notification systems
- Document creation
- Payment systems
- Vehicle manufacturing systems
- File parsers
- Logging systems
- Cloud service providers
Factory Method vs Simple Factory
These two concepts are often confused.
Simple Factory
A single class decides which object to create.
if (type.equals("email"))
return new EmailNotification();
if (type.equals("sms"))
return new SMSNotification();
The factory contains the decision-making logic.
Factory Method
The decision is delegated to subclasses.
NotificationCreator
|
+--- EmailCreator
|
+--- SMSCreator
Therefore, Factory Method provides greater flexibility and supports extension through inheritance.
Advantages of Factory Method
1. Loose Coupling
The client does not need to depend directly on concrete classes.
2. Easy Extension
New product types can be added with minimal changes to existing code.
3. Supports the Open/Closed Principle
The system can be extended without constantly modifying existing code.
4. Centralizes Object Creation
Object creation is separated from the business logic that uses the objects.
5. Improves Maintainability
As applications grow, separating object creation can make the code easier to understand and maintain.
Disadvantages
1. More Classes
Factory Method can introduce additional creator and product classes.
2. Increased Complexity
For very small applications, using a Factory Method may be unnecessary.
3. Inheritance Dependency
The traditional Factory Method relies on subclasses to determine object creation.
When Should You Use Factory Method?
Factory Method is useful when:
- The exact type of object is not known until runtime.
- A system needs to create multiple related types of objects.
- Object creation logic is becoming complicated.
- You want to reduce coupling between the client and concrete classes.
- New object types are expected to be added in the future.
However, a design pattern should not be used simply because it exists. For a small application with only one or two object types, a Factory Method may introduce unnecessary complexity.
Conclusion
The Factory Method Design Pattern is a powerful creational pattern that separates object creation from the code that uses those objects.
Instead of allowing the client to directly create concrete objects, the Factory Method provides a controlled mechanism for creating them.
The key idea is:
Client
↓
Creator
↓
Factory Method
↓
Concrete Product
By using this approach, software can become more loosely coupled, extensible, and maintainable.
Factory Method is particularly useful in large applications where new object types may be introduced frequently. Understanding this pattern also provides a strong foundation for learning other creational patterns such as Abstract Factory, Builder, Singleton, and Prototype.
Top comments (0)