Hook: The Factory Pattern is like ordering at a café: you ask for a drink, and the kitchen decides how to build it.
Question: What is the Factory Pattern in Java?
Answer: The Factory Pattern is a creational design pattern that hides object creation behind a method or class. Instead of calling new everywhere, your code asks a factory for an object and depends on an interface or base class, not a concrete class. That keeps creation rules in one place and makes the code easier to change and test.
Interview-Ready Answer: I use the Factory Pattern when I want to separate object creation from object usage. In Java, that usually means I call something like NotificationFactory.create(type) and get back an interface such as Notification, so the caller does not need to know which concrete class was built. The big win is flexibility: if I add a new product type later, I change the factory in one place instead of scattering new across the codebase.
Detailed Explanation:
The factory pattern is a way to put object creation behind a clean API. The caller says what it wants, and the factory decides which concrete class to build. In Java interviews, people often use the phrase factory pattern loosely, but the formal Gang of Four patterns are Factory Method and Abstract Factory. A simple static factory is also very common in real Java code.
email or sms.null and letting a later NullPointerException happen.if/else, switch, or a map of creators. A creator is just a small function or object whose job is to build the product.EmailNotification, SmsNotification, or something added later.new is simpler.| Approach | Who creates | Flexibility | Best for |
|---|---|---|---|
Direct new | Caller | Low | Simple classes |
| Simple factory | One method | Medium | Runtime choice |
| Factory method | Subclass | High | Pluggable types |
| Abstract factory | Factory object | High | Related families |
A quick mental model: direct new means the caller knows the recipe, while a factory means the caller only knows the order. The factory may create one object, reuse a cached object, or wire a whole object graph. The pattern does not force new instances every time; it only centralizes the decision.
The selection cost is usually tiny. A switch is effectively O(1) for a small number of cases, and a HashMap registry is average O(1) lookup. The real cost is almost always the object construction itself, not the factory call. For most Java services, the difference between direct construction and a factory is measured in microseconds, so choose the pattern for maintainability, not speed. If the factory uses reflection, file I/O, or network calls, the cost can grow quickly and should be justified. There is no special Java version requirement for the pattern; modern Java can make factories cleaner with maps and lambdas, but the basic idea works in every version.
ConcurrentHashMap.Real-World Story: Imagine an e-commerce checkout service that supports card payments, wallet payments, and bank transfers. At first, the team wrote new calls directly inside several controllers and service classes. That worked until the company added a new payment provider for one region and changed the rules for currency-specific adapters.
The bug appeared because one code path still created the old payment class directly, while another used the new provider. Some users saw orders stuck in payment pending, retries spiked, and support tickets said, “I was charged, but the order never completed.” Logs showed messages like Unknown payment type and No API key configured because construction and validation were scattered across the codebase.
After moving creation into a factory, the team had one place to normalize the provider name, validate config, and choose the right payment implementation. That made rollout safer: adding a new provider became a factory change plus tests, not a hunt through multiple services. This is exactly where factories shine in production: they reduce copy-paste creation logic and prevent inconsistent object setup.
import java.util.Locale;
public class FactoryPatternDemo {
public static void main(String[] args) {
String[] requests = {"email", "sms", "push", " EMAIL ", null, "fax"};
for (String type : requests) {
try {
// The caller asks for a product by name and never needs to know the concrete class.
Notification notification = NotificationFactory.create(type);
notification.send("Your order has shipped.");
} catch (IllegalArgumentException ex) {
// A good factory fails fast with a clear message instead of returning null and breaking later.
System.out.println("Cannot create notification for type=" + type + " -> " + ex.getMessage());
}
}
}
}
interface Notification {
void send(String message);
}
class EmailNotification implements Notification {
@Override
public void send(String message) {
System.out.println("[EMAIL] " + message);
}
}
class SmsNotification implements Notification {
@Override
public void send(String message) {
System.out.println("[SMS] " + message);
}
}
class PushNotification implements Notification {
@Override
public void send(String message) {
System.out.println("[PUSH] " + message);
}
}
final class NotificationFactory {
private NotificationFactory() {
// Utility class: prevent accidental instantiation.
}
public static Notification create(String type) {
if (type == null) {
throw new IllegalArgumentException("type must not be null");
}
String normalized = type.trim().toLowerCase(Locale.ROOT);
switch (normalized) {
case "email":
return new EmailNotification();
case "sms":
return new SmsNotification();
case "push":
return new PushNotification();
default:
throw new IllegalArgumentException("Unknown notification type: " + type);
}
}
}Follow-up & Tricky Questions:
new bad in Java? No. Direct new is perfectly fine for simple, stable objects. The factory pattern is for when creation logic is likely to change or needs to be centralized.Common Mistakes:
null for unknown input. Correction: Throw a clear exception or handle absence explicitly.Memory Hook: You order, the kitchen decides. The caller asks for a product, and the factory quietly chooses how to build it.
Cheat Sheet:
new calls.Practice Tasks:
LoggerFactory that creates console and file loggers.WhatsAppNotification type and update the factory with one change only.switch with a Map<String, Supplier<Notification>> registry and compare the design.