A ride-booking app supports Car and Bike rides today. Somewhere in the codebase, five different places directly write Car() or Bike() depending on what the user picked. Now product wants to add Auto (three-wheeler) rides.
Where do you make the change? If the answer is "hunt down all five places and add a third branch to each," you already have a design problem — and you're about to meet its fix.
The pain: creation logic scattered everywhere
# scattered across the codebase, in five different files:
if ride_type == "car":
vehicle = Car()
elif ride_type == "bike":
vehicle = Bike()
# adding "auto" means finding and editing every one of these blocksAsk (from the SOLID lesson): "if I add a new type, do I keep modifying existing code?" Here, clearly yes — in five separate places. That's the exact Open/Closed pressure point Factory is designed to relieve.
A simple factory — the easiest fix
Move the decision into one place instead of five:
class VehicleFactory:
@staticmethod
def create(ride_type):
if ride_type == "car":
return Car()
elif ride_type == "bike":
return Bike()
raise ValueError(f"Unknown ride type: {ride_type}")
# everywhere else in the codebase:
vehicle = VehicleFactory.create(ride_type)Adding auto now means editing one method, not five call sites. This is often called a "Simple Factory" — not one of the two official patterns below, but a completely reasonable interview answer for a straightforward creation problem.
Factory Method — one method per creator
Simple Factory still has an if/else — just consolidated. Factory Method goes one step further: let each subclass decide which concrete class to create, through an overridden method, with zero conditionals anywhere:
class Logistics:
def create_transport(self):
raise NotImplementedError # subclasses decide
def plan_delivery(self):
transport = self.create_transport() # doesn't know or care which one
transport.deliver()
class RoadLogistics(Logistics):
def create_transport(self):
return Truck()
class SeaLogistics(Logistics):
def create_transport(self):
return Ship()
# adding air delivery later = one new class, zero edits above:
class AirLogistics(Logistics):
def create_transport(self):
return Plane()plan_delivery() never changes, no matter how many new logistics types appear — each subclass owns its own creation decision. This is Factory Method: "lets subclasses decide which concrete class to instantiate," letting client code obey OCP by depending only on the abstract Transport interface.
Abstract Factory — families of related objects
Sometimes you don't need one object — you need a matching family of them. A UI toolkit that supports Windows and Mac needs a Windows button with a Windows checkbox, never a Windows button paired with a Mac checkbox:
class UIFactory:
def create_button(self): raise NotImplementedError
def create_checkbox(self): raise NotImplementedError
class WindowsUIFactory(UIFactory):
def create_button(self): return WindowsButton()
def create_checkbox(self): return WindowsCheckbox()
class MacUIFactory(UIFactory):
def create_button(self): return MacButton()
def create_checkbox(self): return MacCheckbox()
# client code just asks its factory for both, and they always match:
def render_form(factory: UIFactory):
button = factory.create_button()
checkbox = factory.create_checkbox()This is Abstract Factory: one factory interface with several creation methods, producing a whole consistent family. For SDE-I/II interviews, understanding Factory Method deeply matters far more than memorising Abstract Factory — reach for it only when the requirement is explicitly about matching families of objects, not single ones.
When a factory is overkill
If you only ever create one class, with no realistic second variant on the horizon, a factory adds a layer of indirection for no benefit.
InvoiceFactory that only ever returns new Invoice(). If there's no real variation to hide, Invoice() directly is the honest, simpler answer.Common mistakes
- Building a factory for a class with no real variants, just for "consistency."
- Confusing Factory Method (one product) with Abstract Factory (a family of related products).
- Forgetting that client code should depend on the abstract product interface, not the concrete classes the factory returns.
- Letting the factory's if/else grow unboundedly instead of ever considering Factory Method's subclass-per-creator approach when the type list keeps expanding.
Quick recap
| Idea | One-liner |
|---|---|
| Pain solved | Object-creation decisions scattered across client code. |
| Simple Factory | One method, one if/else, everyone calls it instead of `new`. |
| Factory Method | Each subclass overrides one method to decide what it creates — zero conditionals. |
| Abstract Factory | One factory interface creates a whole matching family of related objects. |
| Overkill case | One class, no real variants — just use the constructor. |
One thing to remember
A factory exists to hide a real creation decision behind one place — never add one until that decision is actually there to hide.
Practice Zone
Five MCQs, then two reasoning questions.
What problem does the Factory Method pattern solve?
Asked in


How does Factory Method relate to the Open/Closed Principle?
Asked in

What's the key difference between Factory Method and Abstract Factory?
Asked in

You only ever create one class, Invoice, and there's no realistic plan for a second type. Should you build an InvoiceFactory?
Asked in

Which phrase in a requirement is the strongest Factory signal?
Asked in


Think it through, then reveal:
A logistics app has RoadLogistics and SeaLogistics, each needing a different kind of Transport (Truck vs Ship). Client code currently does if mode == 'road': transport = Truck() else: transport = Ship() in five different places. What's the problem, and how does Factory Method fix it?
Asked in

Is a single static method like VehicleFactory.create(type: str) with an if/else inside it "cheating" — does it still count as using the Factory pattern?
Asked in

FAQ
Is a Simple Factory a real Gang-of-Four pattern?
No — it's a common, useful idiom, but the two official creational patterns in this family are Factory Method and Abstract Factory. For SDE-I/II interviews, using a Simple Factory and saying so honestly ("this is a lightweight factory, not the full Factory Method pattern") is a perfectly good answer for straightforward creation problems.
How is Factory different from Builder?
Factory decides which class to instantiate, usually in one step. Builder is about constructing one complex object step by step (many optional parts, assembled gradually) — useful when a constructor would otherwise need a dozen parameters. They solve different pains and are sometimes combined (a factory that internally uses a builder).
Does using a Factory always mean I need an interface?
For Factory Method to buy you anything, yes — client code needs to depend on the abstract product type (e.g. Transport), not the concrete ones, otherwise you've hidden the `new` call but not the coupling to specific classes.
Factory controlled which class gets created. Next, we control which algorithm runs — the pattern almost every LLD design in this course ends up needing — Lesson 5: Strategy Pattern →


