Step 1 Understand it
The problem it solves. If the code that uses an object also decides which concrete to create, every new type means editing that code in many places.
New words in this topic (tap one to see what it means)
Watch it happen
Read the animation as text
- Every notifier implements one interface: send(message). The decision "which class?" lives in ONE place — a factory holding a dictionary from name to class.
- The order service asks the factory for "sms". It never writes SmsNotifier() itself.
- The factory looks "sms" up and returns an SmsNotifier. The service only uses it through the interface: notifier.send("Your order shipped").
- Adding WhatsApp means one new class and one new dictionary entry. No caller changes at all.
Picture it
classDiagram
class Notifier {
<<interface>>
+send(msg)
}
class NotifierFactory {
+create(channel) Notifier
}
Notifier <|.. EmailNotifier
Notifier <|.. SmsNotifier
Notifier <|.. PushNotifier
NotifierFactory ..> Notifier : creates
OrderService --> NotifierFactory : asksThe idea
Factory Method: one method decides which class to create. Abstract Factory: creates whole families of related objects that must match, such as all dark-theme or all light-theme UI parts. Both keep 'new ConcreteClass()' in one place.
How it works, step by step
- Define a common interface: Notifier with send(message).
- Implement it in EmailNotifier, SmsNotifier and PushNotifier.
- Put the 'which class?' decision in one factory, using a dictionary from name to class.
- Callers ask the factory for 'sms' and use the result only through the interface.
- Adding a WhatsAppNotifier means one new class and one new dictionary entry.
Analogy
Ordering from a car factory: you ask for 'a family car', and the factory decides the exact model and parts.
Where the analogy breaks
A car factory has a fixed catalogue. If every new type means editing one big if/else inside the factory, you've just moved the problem. A registry of creators keeps it open for extension.
Example
NotifierFactory.create('sms') returns an SmsNotifier, and the order service just calls notifier.send().
Must-know points
- Use it when the exact class depends on input or configuration.
- Factory Method: one product, a method decides. Abstract Factory: families of related products.
- A registry dictionary avoids long if/else chains.
- The 'simple factory' (one create function) is the usual interview version.
Common mistakes
- A factory that's just a giant if/else edited for every new type.
- Factories for objects that only ever have one type.
class EmailNotifier:
def send(self, msg): return f"email: {msg}"
class SmsNotifier:
def send(self, msg): return f"sms: {msg}"
class NotifierFactory:
_registry = {"email": EmailNotifier, "sms": SmsNotifier}
@classmethod
def create(cls, channel):
return cls._registry[channel]() # callers never name a concrete class
NotifierFactory.create("sms").send("Your order has shipped")Step 2 Go further (free, optional)
Optional. The notes above are written to be enough on their own. These free resources give a second explanation and extra practice.
-
Read
Refactoring.Guru, free
-
Read
Refactoring.Guru, free
Step 3 Practise
Try each exercise yourself first: on paper, out loud or in code. Then open the answer and compare it with yours.
-
ExplainSay it in plain words in under a minute, with no notes.
Explain Factory Method and Abstract Factory with one example each.
Show answer
Both put the decision "which concrete class do I create?" in one place, so the rest of the code never names a concrete class.
Factory Method: a single method creates one product and decides which class it is. NotifierFactory.create("sms") returns an SmsNotifier; the order service only knows it got "a notifier" and calls send(). Adding a channel changes the factory, not the callers.
Abstract Factory: an object that creates a whole family of related products that must match. A UI has a DarkThemeFactory that makes a dark button, a dark checkbox and a dark menu, and a LightThemeFactory that makes the light versions. The screen asks its factory for parts, so it can never mix a dark button with a light checkbox. Switching theme means switching one factory.
-
DrawSketch the diagram (or class diagram) from memory.
Draw NotifierFactory, the Notifier interface and three notifiers.
Show answer
The caller talks to the factory and to the Notifier interface only. The factory's registry maps a channel name to a class; each notifier implements the same send() method, so whichever one comes back is used the same way.
textOrderService ── create("sms") ──► NotifierFactory │ - _registry: │ "email" → EmailNotifier │ "sms" → SmsNotifier │ "push" → PushNotifier │ + create(channel): Notifier │ uses ▼ «interface» Notifier + send(msg) △ △ △ ┊ ┊ ┊ EmailNotifier SmsNotifier PushNotifier -
ApplyUse it in a real design question and say exactly where it fits.
Add a 'push' notifier without changing the logic inside create().
Show answer
create() is exactly the lesson's one line. The factory gains a register() method, used as a , so a new notifier registers itself where it is defined. Adding "push" touches no existing code: one new class, marked with the channel name.
pythonclass EmailNotifier: def send(self, msg): return f"email: {msg}" class SmsNotifier: def send(self, msg): return f"sms: {msg}" class NotifierFactory: _registry = {"email": EmailNotifier, "sms": SmsNotifier} @classmethod def register(cls, channel): def add(notifier_class): cls._registry[channel] = notifier_class return notifier_class return add @classmethod def create(cls, channel): return cls._registry[channel]() # unchanged @NotifierFactory.register("push") # the new notifier registers itself class PushNotifier: def send(self, msg): return f"push: {msg}" print(NotifierFactory.create("push").send("Your order has shipped")) # push: Your order has shipped print(NotifierFactory.create("sms").send("Code 4821")) # sms: Code 4821 -
Trade-offsSay what it costs, when not to use it, and the alternative.
When is a factory just unnecessary indirection?
Show answer
• There is only one concrete class, and no real prospect of another: just call its constructor.
• The caller already knows exactly which class it needs: a factory that takes "email" and returns EmailNotifier() adds a lookup and a file for no gain.
• Construction is trivial: a factory that only wraps a constructor is a layer to read through, not a design.
• In Python, a class is already a factory: you can pass the class itself (or a function) to whoever needs to create objects, without a Factory class around it.A factory earns its place when the choice depends on something only known at runtime (configuration, user input, the country), when creating the object is complicated (several steps, dependencies to wire), or when a family of objects must match (Abstract Factory).
Step 4 Interview-ready, then prove it
Your interview answer
About 20 to 40 seconds, said out loud. Practise it until it sounds like you, not like notes.
A factory centralises object creation: callers ask for a type by name or configuration and get an object behind a common interface, so adding a new type doesn't change the calling code. Abstract Factory extends this to whole families of matching objects.
Follow-up questions
Factory or ?
A factory picks which class to create, in one step. A builder assembles one complex object step by step.
Tick each check when you can do it without notes
A topic is finished when you pass all four checks, not when you finish a video. Be strict: if you needed your notes, it is not ticked yet.
- Explain Say it in plain words in under a minute, with no notes.
- Draw Sketch the diagram (or class diagram) from memory.
- Apply Use it in a real design question and say exactly where it fits.
- Trade-offs Say what it costs, when not to use it, and the alternative.
0 of 4 checks ticked.
Saved in this browser. Back it up or move it to another device.