What Problem It Solves
Object creation logic scattered across client code means every new type requires editing multiple call sites. Factory centralizes creation, giving you one place to change when types change.
Naive (Without Factory) โ DON'T
if (type.equals("CAR")) spot = new CarSpot();
else if (type.equals("BIKE")) spot = new BikeSpot();
else if (type.equals("TRUCK")) spot = new TruckSpot();Every if-else chain repeated wherever spots are needed.
Simple Factory vs Factory Method
| Aspect | Simple Factory | Factory Method |
|---|---|---|
| Structure | One factory class with a switch/registry | Abstract creator with subclass per product |
| When to use | Few product types, stable creation | Creation varies per product type |
| Extension | Add to the switch/registry | Add a new Creator subclass |
| Interview fit | 90% of LLD problems | Use when different types need different setup |
Common Interview Traps
| Trap | Why | Fix |
|---|---|---|
Factory returns null on unknown type | Client forgets null check โ NPE | Throw explicit exception or return Optional |
| Factory depends on concrete types | Violates DIP โ factory knows all types | Registry-based factory avoids switch |
| Factory does too much | Mixes validation, creation, and caching | Factory should only create. Keep it thin. |
Where Factory Appears in LLD Problems
| Problem | Product | Factory |
|---|---|---|
| Parking Lot (#1) | ParkingSpot | ParkingSpotFactory.createSpot(type, id) |
| Chess (#9) | ChessPiece | ChessPieceFactory.createPiece(type, color) |
| Vending Machine (#7) | Product / Payment | ProductFactory, PaymentHandlerFactory |
| Elevator (#3) | Command | CommandFactory.create(type, params) |
| Splitwise (#5) | Split Strategy | SplitStrategyFactory.create(type, amounts) |
| Notification (#18) | Channel | NotificationChannelFactory.create(channelType) |
With Factory โ DO
// โโโ EXAMPLE 1 โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// WHAT WE ARE IMPLEMENTING:
// A notifications delivery framework routing alerts via Email, SMS, or Push
// channels.
//
// WHERE THE PATTERN FITS IN:
// NotificationFactory acts as the Creator. EmailNotificationFactory and
// SMSNotificationFactory represent Concrete Creators overriding the factory
// method to return matching product subclasses.
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// --- Products ---
interface ParkingSpot {
String getId();
double getHourlyRate();
}
class CarSpot implements ParkingSpot {
private final String id;
public CarSpot(String id) { this.id = id; }
public String getId() { return id; }
public double getHourlyRate() { return 20.0; }
}
class BikeSpot implements ParkingSpot {
private final String id;
public BikeSpot(String id) { this.id = id; }
public String getId() { return id; }
public double getHourlyRate() { return 10.0; }
}
class TruckSpot implements ParkingSpot {
private final String id;
public TruckSpot(String id) { this.id = id; }
public String getId() { return id; }
public double getHourlyRate() { return 40.0; }
}
// --- Factory (centralized creation) ---
enum SpotType { CAR, BIKE, TRUCK }
class ParkingSpotFactory {
public static ParkingSpot createSpot(SpotType type, String id) {
return switch (type) {
case CAR -> new CarSpot(id);
case BIKE -> new BikeSpot(id);
case TRUCK -> new TruckSpot(id);
};
}
}
// --- Client code ---
public class Main {
public static void main(String[] args) {
ParkingSpot carSpot = ParkingSpotFactory.createSpot(SpotType.CAR, "A1");
ParkingSpot bikeSpot = ParkingSpotFactory.createSpot(SpotType.BIKE, "B2");
System.out.println("Car spot: " + carSpot.getId() + " Rate: " + carSpot.getHourlyRate());
System.out.println("Bike spot: " + bikeSpot.getId() + " Rate: " + bikeSpot.getHourlyRate());
}
}Review
Help Us Improve
How helpful was this walkthrough?
Click a star to rate. We actively use this feedback to refine and update our system design content.
Placeholder
Discussion
Share your thoughts, ask questions, or help others.
Loading comments...