Chaturmind
LearnDSASystem DesignBlogPremium
Sign inGet started
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML

Company

  • Blog
  • Premium
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight
HomeLearnSystem DesignLow-Level Design & Design PatternsCreational Design Patterns
✓ FreeIntermediate· 7 min read

Factory & Abstract Factory

Factory method delegates 'which subclass to build' to one place; Abstract Factory does the same for entire families of related objects. Built through a NotificationFactory exercise.

Published September 22, 2026


Factory & Abstract Factory

Factory Method: delegating creation instead of scattering new

The problem Factory solves: object-creation logic (which concrete class to instantiate, based on some condition) tends to get copy-pasted at every call site that needs one, and every new type means hunting down and editing every one of those call sites.

interface Notifier { void send(String to, String message); }
class EmailNotifier implements Notifier { public void send(String to, String message) { /* ... */ } }
class SmsNotifier implements Notifier { public void send(String to, String message) { /* ... */ } }
class PushNotifier implements Notifier { public void send(String to, String message) { /* ... */ } }

class NotifierFactory {
    static Notifier create(String type) {
        return switch (type) {
            case "EMAIL" -> new EmailNotifier();
            case "SMS" -> new SmsNotifier();
            case "PUSH" -> new PushNotifier();
            default -> throw new IllegalArgumentException("Unknown type: " + type);
        };
    }
}

Callers depend only on NotifierFactory.create(type) and the Notifier interface — never on a concrete class directly. Adding a new channel means editing the factory in one place, not hunting down every new EmailNotifier() scattered through the codebase. Note this is still technically a single point of if/switch on type — it doesn't eliminate branching on type entirely (that's what Strategy + polymorphism does more fully), but it does centralize it to exactly one place instead of many.

Abstract Factory: a factory of factories

Factory Method produces one type of object. Abstract Factory produces a family of related objects that need to stay consistent with each other.

interface Button { void render(); }
interface Checkbox { void render(); }

// Family 1: Windows-style widgets
class WindowsButton implements Button { public void render() { /* Windows look */ } }
class WindowsCheckbox implements Checkbox { public void render() { /* Windows look */ } }

// Family 2: Mac-style widgets
class MacButton implements Button { public void render() { /* Mac look */ } }
class MacCheckbox implements Checkbox { public void render() { /* Mac look */ } }

interface UIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

class WindowsUIFactory implements UIFactory {
    public Button createButton() { return new WindowsButton(); }
    public Checkbox createCheckbox() { return new WindowsCheckbox(); }
}

class MacUIFactory implements UIFactory {
    public Button createButton() { return new MacButton(); }
    public Checkbox createCheckbox() { return new MacCheckbox(); }
}

The guarantee Abstract Factory provides that plain Factory Method doesn't: given one UIFactory implementation, every widget it produces belongs to the same family — code using a WindowsUIFactory can never accidentally end up with a MacCheckbox next to a WindowsButton, because the factory itself is the single source of truth for which family is active.

Design exercise: NotificationFactory producing Email/SMS/Push notifiers

The example above already builds this, but worth stating the design decision explicitly: is this Factory Method or Abstract Factory? It's Factory Method — Notifier is a single interface, and the factory just picks which concrete implementation to hand back based on a type parameter. It would become Abstract Factory only if, say, each notification channel needed a family of related objects (a Notifier and a matching MessageFormatter and a matching DeliveryTracker, all required to be the same "brand" for a given channel) — at that point, one factory method per family member, grouped behind one NotificationFactory interface, is the Abstract Factory shape.

Follow-up questions this topic invites — and their answers

Q: Isn't Factory Method just an if/switch statement with extra steps? A: The value isn't eliminating the conditional — it's centralizing it. Every call site that needs a Notifier depends on the factory and the interface, never on a concrete class; the conditional exists in exactly one place instead of being copy-pasted at every construction site, which is what actually makes adding a new type a one-file change.

Q: When would you reach for Abstract Factory over Factory Method? A: When objects genuinely need to be created in matching sets that must stay internally consistent — cross-platform UI toolkits (the classic example), or a multi-tenant system where every object created for a given tenant must come from that tenant's specific configuration family.

Q: How does Factory Method relate to Dependency Inversion? A: They solve different problems that often appear together — DIP is about a consumer depending on an abstraction rather than a concrete class; Factory Method is about centralizing the decision of which concrete class implements that abstraction. A DIP-compliant class typically receives its dependency through the constructor, having been built by a factory (or a DI container acting as one) somewhere upstream.

Q: Can a Spring @Bean method be considered a Factory Method? A: Functionally, yes — a @Bean method is exactly a factory: it decides which concrete implementation to construct and hand back, and Spring's container acts as the caller requesting an instance by type, rather than any application code calling new directly.

Previous

Singleton Pattern

Next

Builder Pattern

AI Tutor

Lesson: Factory & Abstract Factory

Quick actions

AI responses can be inaccurate. Verify critical information.