Factory Method Pattern
The Factory Method Pattern provides an interface for creating objects, but allows subclasses or a factory class to decide which concrete class to instantiate.
Instead of creating objects using new, object creation is delegated to a factory.
Why Factory Method Exists
Direct object creation causes:
- Tight coupling
- Difficult changes
- Violations of Open/Closed Principle
- Hard-to-test code
Factory Method solves this by:
- Hiding object creation logic
- Decoupling client code from concrete classes
- Allowing easy extension
Core idea:
Separate object creation from object usage.
Problem Without Factory
Banking Example: Payment Processing
public class PaymentService {
public void pay(String type) {
if ("UPI".equals(type)) {
new UpiPayment().process();
} else if ("CARD".equals(type)) {
new CardPayment().process();
}
}
}
Problems ❌
- if-else grows with new types
- Class must be modified every time
- Violates Open/Closed Principle
- Hard to test and extend
Factory Method Solution
Step 1️⃣ Define a Common Interface
public interface PaymentProcessor {
void process();
}
Step 2️⃣ Create Implementations
public class UpiPayment implements PaymentProcessor {
public void process() {
System.out.println("Processing UPI payment");
}
}
public class CardPayment implements PaymentProcessor {
public void process() {
System.out.println("Processing Card payment");
}
}
Step 3️⃣ Create the Factory
public class PaymentFactory {
public static PaymentProcessor getPaymentProcessor(String type) {
return switch (type) {
case "UPI" -> new UpiPayment();
case "CARD" -> new CardPayment();
default -> throw new IllegalArgumentException("Invalid payment type");
};
}
}
Step 4️⃣ Use the Factory
public class PaymentService {
public void pay(String type) {
PaymentProcessor processor = PaymentFactory.getPaymentProcessor("UPI");
processor.process();
}
}
Benefits Achieved ✅
- Client code does not know concrete classes
- Object creation logic is centralized
- Easy to add new payment types
- Better readability and testability
How This Relates to Spring
You use Factory Method daily in Spring without realizing it.
Example: BeanFactory
ApplicationContext context = ...
MyService service = context.getBean(MyService.class);
Spring:
- Decides which implementation to return
- Manages creation
- Manages lifecycle
👉 Spring itself is a massive Factory implementation
Factory Method vs Simple new
| Aspect | new | Factory |
|---|---|---|
| Coupling | Tight | Loose |
| Extensibility | Poor | High |
| Testability | Low | High |
| OCP | Violated | Followed |
When to Use Factory Method
Use it when:
- Object creation logic is complex
- Multiple implementations exist
- You expect new types in future
- Creation should be centralized
When NOT to Use Factory
Avoid when:
- Only one implementation
- No variation expected
Do not over-engineer.
Banking / Enterprise Usage
Common factory usages:
- Payment processors
- Notification channels (Email/SMS/Kafka)
- Interest calculation strategies
- Report generators
- File parsers
I used Factory Method pattern to create different payment processors based on payment type. It helped decouple object creation from business logic and allowed easy extension without modifying existing code.
Summary
- Factory Method hides object creation
- Improves extensibility
- Reduces coupling
- Widely used in Spring internally
- Very common in real projects