Factory Method โ Creational design pattern with UML diagrams, Java implementation, and real-world examples.
Creational
Factory Method Pattern
Let subclasses decide which class to instantiate. A foundational creational pattern — the backbone of every plugin system, driver loader, and framework extension point.
You are building a notification service. Today you send only emails. The code works fine — NotificationService creates a new EmailNotification directly and calls send(). Then the product team asks for SMS. Then push notifications. Every time a new channel is added, you crack open NotificationService, add another if/else branch, import another concrete class, and re-test everything. The service that uses notifications is now tightly coupled to every type of notification. One class knows too much.
Naive approach — hardcoded new calls, growing conditional
// โ Every new channel requires editing this classclassNotificationService {
public voidnotify(String type, String message) {
if (type.equals("email")) {
newEmailNotification().send(message); // hardcoded
} else if (type.equals("sms")) {
newSmsNotification().send(message); // hardcoded
} else if (type.equals("push")) {
newPushNotification().send(message); // hardcoded
}
// Slack? Webhook? Pigeon? More branches…
}
}
What goes wrong:
Open/Closed violation — adding a channel means modifying existing code, not extending it
Tight coupling — the service imports and instantiates every concrete notification class
Scattered new calls — if creation logic changes (e.g. SMS needs an API key), you hunt down every new SmsNotification()
Untestable — you cannot inject a mock notification because creation is hardcoded inside the method
Without Factory Method — service coupled to every concrete product
This is the problem Factory Method solves — move the new call into a method that subclasses override, so the service works with any notification type without knowing which concrete class it is creating.
02
Section Two ยท The Pattern
What Is Factory Method?
Factory Method is a creational pattern that defines an interface for creating an object but lets subclasses decide which class to instantiate. Instead of calling new ConcreteProduct() directly, the client calls an abstract method — createNotification() — and the subclass plugs in the right product. The creator code works with the product interface only, never touching a concrete class.
GoF Intent: “Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.” — Gamma, Helm, Johnson, Vlissides (1994)
Analogy — a franchise restaurant: The corporate headquarters (the Creator) defines the complete process for serving a meal — take the order, prepare food, serve, collect payment. But each franchise location (the Concrete Creator) decides which menu items to prepare. A Tokyo franchise creates sushi; a New York franchise creates burgers. HQ never names a specific dish — it just calls prepareMainCourse() and trusts the local kitchen to supply the right product. That’s Factory Method: the algorithm stays the same, but the product varies by subclass.
Key insight: Factory Method is inheritance applied to object creation. The creator class defines when and how to use a product; the subclass supplies which product. This is what separates it from Abstract Factory (which creates families of products) and from a simple static factory (which is just a utility method, not a subclass hook).
Creator declares an abstract createProduct() method
▶
Creator code only depends on the product interface, not any concrete class
Each Concrete Creator overrides createProduct()
▶
Adding a new product type means adding one new subclass — no existing code changes
Client code works with the Creator type
▶
Runtime polymorphism selects the right factory at runtime — Open/Closed Principle satisfied
Product interface is the only contract
▶
New channels (Slack, Webhook) plug in without touching the service that sends notifications
03
Section Three ยท Anatomy
Participants & Structure
Participant
Role
In the Analogy
Product
The interface (or abstract class) that all products implement. The creator works against this type only.
A “main course” — the contract every kitchen must fulfil.
Concrete Product
A specific implementation of the product interface. Each one encapsulates its own creation and behaviour logic.
Sushi, Burger, Pizza — each franchise’s local dish.
Creator
An abstract class (or interface) that declares the factory method createProduct() and contains the business logic that uses the product.
Corporate headquarters — defines the meal-serving algorithm.
Concrete Creator
A subclass of Creator that overrides createProduct() to return a specific Concrete Product.
The Tokyo franchise, the New York franchise — each supplies its own dish.
Factory Method — UML Class Diagram
Four participants, two hierarchies:
Factory Method always has a parallel structure — one hierarchy for creators, one for products.
Each concrete creator knows about exactly one concrete product.
The creator and the product are connected only through their abstract types.
04
Section Four ยท How It Works
The Pattern In Motion
Scenario: A notification system where the client picks a creator at startup, and the creator handles everything from there.
Step 1 — Client picks a creator: creator = new SmsCreator()
▶
The client knows which channel it wants, but never touches the concrete notification class directly.
Step 2 — Client calls creator.sendNotification("Your order shipped")
▶
Inside sendNotification(), the creator calls its own abstract createNotification() method — the factory method.
Step 3 — SmsCreator.createNotification() returns new SmsNotification()
▶
The concrete creator supplies the concrete product. This is the only place new SmsNotification() appears in the entire codebase.
Step 4 — Creator calls notification.send(message)
▶
The creator works with the Notification interface. It does not know or care that it’s an SMS. Swapping to email means swapping the creator, not editing any logic.
Before / After — hardcoded new vs. factory method
The pattern in pseudocode
abstract classNotificationCreator {
// The factory method โ subclasses supply the productabstractNotificationcreateNotification();
// Template method that USES the productpublic voidsendNotification(String msg) {
Notification n = createNotification(); // factory method call
n.format(msg);
n.send(msg); // works with interface only
}
}
classSmsCreatorextendsNotificationCreator {
NotificationcreateNotification() {
return newSmsNotification(); // only place SMS is named
}
}
Factory Method + Template Method:
Notice how sendNotification() is a Template Method — it defines the algorithm (create, format, send) and delegates one step (createNotification()) to the subclass.
These two patterns are natural companions; Factory Method is often a single step inside a Template Method.
05
Section Five ยท Java Stdlib
You Already Use This
Factory Method is everywhere in the JDK. Whenever you see a static or instance method whose return type is an interface and whose concrete product is decided internally, you’re looking at a factory method.
IN JAVA
Example 1java.util.Calendar.getInstance() — returns a Calendar subclass (GregorianCalendar, JapaneseImperialCalendar, etc.) based on the default locale and timezone. The caller works with the Calendar interface — never names the concrete class.
Example 2java.nio.charset.Charset.forName("UTF-8") — returns a Charset subclass appropriate for the named encoding. The concrete product varies by JDK vendor and platform.
Example 3java.util.Collection.iterator() — every Collection subclass (ArrayList, HashSet, LinkedList) overrides iterator() to return its own concrete Iterator. The caller only touches the Iterator<E> interface. This is a textbook factory method — the product is an Iterator, and each collection is a concrete creator.
Stdlib usage — Calendar.getInstance()
// You never write: new GregorianCalendar() โ you call the factory methodCalendar cal = Calendar.getInstance();
System.out.println(cal.getClass().getSimpleName()); // GregorianCalendar
System.out.println(cal.get(Calendar.YEAR)); // 2026// Change locale โ different concrete product, same Calendar interfaceCalendar jpCal = Calendar.getInstance(
Locale.forLanguageTag("ja-JP-u-ca-japanese")
);
System.out.println(jpCal.getClass().getSimpleName()); // JapaneseImperialCalendar
Stdlib usage — Collection.iterator() as Factory Method
// ArrayList.iterator() returns ArrayList$Itr// LinkedList.iterator() returns LinkedList$ListItr// The caller only sees Iterator<E>List<String> names = List.of("Alice", "Bob");
Iterator<String> it = names.iterator(); // factory method callwhile (it.hasNext()) System.out.println(it.next());
Static factory โ Factory Method pattern:
Calendar.getInstance() is technically a static factory method (a convenience method, not an overridable subclass hook).
The GoF Factory Method pattern requires inheritance — an abstract createProduct() that concrete subclasses override.
Collection.iterator() is the purer example: each Collection subclass overrides the method to return its own Iterator.
06
Section Six ยท Implementation
Build It Once
Domain: Notification Service (Email, SMS, Push). Each creator overrides the factory method to supply its channel. The client picks a creator and never touches a concrete notification class.
To add a Slack channel, create SlackNotification implements Notification and SlackCreator extends NotificationCreator.
That’s it — two new files, zero edits to existing classes. The Open/Closed Principle in action.
07
Section Seven ยท Watch Out
Common Mistakes
Mistake #1 — Returning concrete type instead of product interface: When the factory method is declared to return a concrete class instead of the product interface, callers become tightly coupled to the implementation again — defeating the entire purpose of the pattern.
✗ Wrong — returns concrete type
// โ Caller now depends on EmailNotification directlyabstractEmailNotificationcreateNotification();
✔ Correct — returns product interface
// โ Caller only knows about the Notification interfaceabstractNotificationcreateNotification();
Mistake #2 — Putting business logic inside the factory method:
The factory method’s only job is to create and return a product.
Sending the notification, logging, or calling APIs inside createNotification() breaks the Single Responsibility Principle and makes the subclass impossible to test in isolation.
Business logic belongs in sendNotification() (the template method), not in the factory method.
Mistake #3 — Confusing Factory Method with static factory or Abstract Factory:
Static factory (Calendar.getInstance()) is a utility method — no inheritance, no subclass hook
Factory Method is an abstract method overridden in a subclass hierarchy
Abstract Factory creates families of related products (e.g. Email + EmailTemplate + EmailLogger all from one factory)
Using a static if/else inside a “factory method” is not the pattern — that’s just a static factory with extra steps.
Mistake #4 — Creating too many creator subclasses for trivial variation:
If the only difference between two creators is a configuration value (e.g. an API endpoint URL), a parameterized factory or a constructor argument is simpler than two subclasses.
Factory Method shines when the product type itself changes — not just its configuration.
08
Section Eight ยท Decision Guide
When To Use Factory Method
Use Factory Method When
You don’t know ahead of time which class to instantiate — the type is determined at runtime or by configuration
You want to give subclasses control over which product to create — the framework defines the algorithm, the app defines the product
Adding a new product variant must not require changing existing code — Open/Closed Principle is a hard requirement
You want creation logic centralised in one place — so changing how a product is built means editing one class, not hunting down every new call
Avoid Factory Method When
There is only one product type and it will never change — the extra hierarchy adds complexity for no gain
You need to create families of related products that must be used together — use Abstract Factory instead
The variation is only a configuration value (URL, timeout, name) — a constructor argument or builder is simpler
Factory Method vs. Confused Patterns
Pattern
Creates
Mechanism
When to pick it
Factory Method ← this
One product type
Abstract method overridden in subclass
Subclass decides which product
Abstract Factory
Family of related products
Interface of multiple factory methods
Products must be used together (e.g. UI themes)
Static Factory Method
One product type
Static utility method (no subclass)
Simple creation, no polymorphism needed
Builder
One complex product
Step-by-step construction
Product has many optional fields or steps
Decision Flowchart
09
Section Nine ยท Practice
Problems To Solve
Factory Method problems test your ability to identify where object creation should be delegated to a subclass, and whether you can extend a system without touching existing code.
Difficulty
Problem
Key Insight
Easy
Document Parser Factory Build a system that parses CSV, JSON, and XML files. The client calls parser.parse(file) and should not know which parser it’s using.
Abstract DocumentParser with factory method createReader(). Each subclass returns CsvReader, JsonReader, or XmlReader. The parse algorithm is in the abstract class.
Medium
Payment Gateway Integration A checkout service must support Stripe, PayPal, and CashOnDelivery. Each gateway has different auth and charge APIs. The checkout flow is identical for all.
Abstract PaymentCreator with factory method createGateway(). Concrete creators return the appropriate PaymentGateway implementation. The checkout flow lives in the abstract creator โ it calls gateway.charge(amount) via interface.
Medium
UI Button Factory A cross-platform UI toolkit needs to render buttons differently on Windows, Mac, and Web. The rendering logic is in the button; the app only creates buttons via a factory.
Abstract Dialog creator with factory method createButton(). Each platform subclass returns its native button. The dialog renders the button by calling button.render() โ interface only. This is the classic GoF example.
Hard
Plugin Loader Design a system that loads export plugins at runtime from a config file (“pdf”, “csv”, “xlsx”). Unknown plugin types should throw a descriptive error. New plugins should be addable without changing the loader.
Use a Map<String, Supplier<ExportPlugin>> as a registry. Register each factory in a static block or via DI. The loader calls registry.get(type).get() โ this is Factory Method combined with a Registry pattern. The hard part: graceful error handling and hot-reload safety.
Interview Tip:
When asked to implement Factory Method, the interviewer wants to see: (1) a product interface, not a concrete return type; (2) an abstract creator with both the factory method and the template method that uses it; (3) at least two concrete creators; (4) a driver that works only with abstract types.
If you add a new product without touching the abstract creator, you’ve got it right.