Factory Method Pattern: The Easiest Guide
1. The Core Concept (The "What")
"Define an interface for creating an object, but let subclasses decide which class to instantiate."
Think of it as outsourcing the creation logic. Instead of your main code using the new keyword directly to create specific objects, you ask a "Factory" to do it for you.
2. The Analogy (The "Hook")
The Logistics Company
Imagine you run a logistics company.
• Initially: You only use Trucks. Your code is full of new Truck().
• Expansion: You start shipping by sea. Now you need Ships.
• The Problem: If you hardcoded new Truck() everywhere, you have to rewrite your entire codebase to handle new Ship().
• The Solution (Factory Method): You create a standard method called createTransport().
• The Road Department (Factory A) returns a Truck.
• The Sea Department (Factory B) returns a Ship.
You (the client) just call createTransport() and don't care how it's made, just that you get something that delivers cargo.
3. The Java Example
Here is a clean, compilable example using the Logistics analogy.
// ===============================
// 1. THE PRODUCT INTERFACE
// Everyone agrees on what a "Transport" object must do.
// ===============================
interface Transport {
void deliver();
}
// ===============================
// 2. CONCRETE PRODUCTS
// The actual objects we want to create.
// ===============================
class Truck implements Transport {
@Override public void deliver() {
System.out.println("Delivering by land in a box.");
}
}
class Ship implements Transport {
@Override public void deliver() {
System.out.println("Delivering by sea in a container.");
}
}
// ===============================
// 3. THE CREATOR (FACTORY)
// Defines the method that "manufactures" the object.
// ===============================
abstract class Logistics {
// FACTORY METHOD — subclasses MUST implement this
abstract Transport createTransport();
// Business logic uses the product without knowing its exact type
public void planDelivery() {
Transport t = createTransport();
t.deliver();
}
}
// ===============================
// 4. CONCRETE CREATORS
// These decide specifically what to create.
// ===============================
class RoadLogistics extends Logistics {
@Override Transport createTransport() {
return new Truck(); // RoadLogistics creates Trucks
}
}
class SeaLogistics extends Logistics {
@Override Transport createTransport() {
return new Ship();
// SeaLogistics creates Ships
}
}
// ===============================
// 5. MAIN EXECUTION
// ===============================
public class FactoryPatternDemo {
public static void main(String[] args) {
// Use road logistics
Logistics roadLogistics = new RoadLogistics();
roadLogistics.planDelivery();
// Output: Delivering by land in a box.
// Switch to sea logistics without changing planDelivery()
Logistics seaLogistics = new SeaLogistics();
seaLogistics.planDelivery();
// Output: Delivering by sea in a container.
}
}4. Cheat Sheet for Memorization
• Goal: Loose coupling. Separation of concerns.
• Key components:
1. Product (Interface)
2. Concrete Product (The actual object)
3. Creator (Abstract class declaring the factory method)
4. Concrete Creator (Overrides the method to return a specific product)
One-Liner to Remember:
"Don't use new directly; let a subclass handle the glue"
5. When to use it?
• When you don't know beforehand the exact types and dependencies of the objects your code should work with.
• When you want to provide users of your library or framework with a way to extend its internal components.
Refferences