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.

Overview ยท Creational ยท Singleton ยท Factory Method ยท Abstract Factory ยท Builder ยท Prototype ยท Adapter ยท Bridge ยท Composite ยท Decorator ยท Facade ยท Flyweight ยท Proxy ยท Observer ยท Strategy ยท Command ยท Template Method ยท Chain of Resp. ยท State ยท Mediator ยท Iterator ยท Visitor ยท Memento ยท Interpreter
Category: Creational Difficulty: Foundational Interview: Tier 1 Confused with: Abstract Factory
01
Section One ยท The Problem

Why Factory Method Exists

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 class class NotificationService { public void notify(String type, String message) { if (type.equals("email")) { new EmailNotification().send(message); // hardcoded } else if (type.equals("sms")) { new SmsNotification().send(message); // hardcoded } else if (type.equals("push")) { new PushNotification().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
NotificationService EmailNotification SmsNotification PushNotification ✗ new ConcreteClass() scattered — violates Open/Closed Principle

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
«abstract» NotificationCreator + sendNotification(msg) + createNotification() : Notification ← factory method (abstract) EmailCreator + createNotification() SmsCreator + createNotification() «interface» Notification + send(msg : String) : void + getChannel() : String Email + send(msg) Sms + send(msg) uses «creates» creates » ■ Blue = abstract / interface ■ Green = concrete - - ▶ = creates (gold dashed) ▷ solid = inherits ▷ dashed = implements
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 3SmsCreator.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
BEFORE — hardcoded creation Service Email SMS Push ✗ coupled to all AFTER — Factory Method Client Creator abstract Notification interface EmailC SmsC Email / Sms creates ✔ Client depends only on abstractions ✔ New channel = new subclass, zero edits
The pattern in pseudocode
abstract class NotificationCreator { // The factory method โ€” subclasses supply the product abstract Notification createNotification(); // Template method that USES the product public void sendNotification(String msg) { Notification n = createNotification(); // factory method call n.format(msg); n.send(msg); // works with interface only } } class SmsCreator extends NotificationCreator { Notification createNotification() { return new SmsNotification(); // 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 1 java.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 2 java.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 3 java.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 method Calendar 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 interface Calendar 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 call while (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.

Java — Factory Method Notification System (core)
// โ”€โ”€ Product interface โ”€โ”€ interface Notification { void send(String message); String getChannel(); } // โ”€โ”€ Concrete Products โ”€โ”€ class EmailNotification implements Notification { public void send(String msg) { System.out.println("[EMAIL] " + msg); } public String getChannel() { return "Email"; } } class SmsNotification implements Notification { public void send(String msg) { System.out.println("[SMS] " + msg); } public String getChannel() { return "SMS"; } } // โ”€โ”€ Abstract Creator โ”€โ”€ abstract class NotificationCreator { // Factory method โ€” subclasses decide which product abstract Notification createNotification(); // Business logic uses the product interface only public void sendNotification(String msg) { Notification n = createNotification(); System.out.println("Sending via " + n.getChannel()); n.send(msg); } } // โ”€โ”€ Concrete Creators โ”€โ”€ class EmailCreator extends NotificationCreator { Notification createNotification() { return new EmailNotification(); } } class SmsCreator extends NotificationCreator { Notification createNotification() { return new SmsNotification(); } }
Extending the system:
  • 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 directly abstract EmailNotification createNotification();
✔ Correct — returns product interface
// โœ“ Caller only knows about the Notification interface abstract Notification createNotification();
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
Need to decouple object creation from use? No Use new directly Yes Create families of related products? Yes Abstract Factory No Subclass decides which product? Yes Factory Method No Static Factory or Builder
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.