Back to Creational: Singleton, Factory, Builder, Prototype
Q7Question 7 of 12

What is the difference between the Factory and Abstract Factory patterns

Key Concepts
  • Factory produces one product from one hierarchy; Abstract Factory produces a matching family of products.
  • Factory answers "which one concrete class?"; Abstract Factory answers "which consistent set of classes?"
  • Abstract Factory has a factory interface with one method per product; each concrete factory produces a matching family.
  • Swapping the Abstract Factory swaps the entire family at once, keeping products consistent.
  • Use Factory for one product whose type varies; use Abstract Factory when products must stay consistent as a set.
  • Abstract Factory has more machinery; only use it when family consistency genuinely matters.

Definition

Factory produces one product; Abstract Factory produces a whole matching family of products through a factory of factories.
  • Factory (Factory Method) – creates a single product from one hierarchy by choosing the concrete class behind a method.
  • Abstract Factory – creates families of related products that are designed to be used together; each concrete factory produces one complete, consistent family.
  • Key difference – Factory decides one product; Abstract Factory decides a matching set and guarantees they belong together.
  • Swapping – swapping an Abstract Factory swaps the entire family at once.
  • Guidance – use Abstract Factory only when product consistency genuinely matters.

At the National Bank of India, the Factory is the single counter that hands Rajesh the one thing he asked for, such as a savings-account kit. The Abstract Factory is the regional branch office that hands him a whole matched set for his region: the regional form, the regional card design, and the regional cheque book, all guaranteed to belong to the same region.

Understanding the Concepts

How does the Factory pattern work?

Factory has one product interface and one factory method that returns one product.

JAVA
package com.bank.service;

import java.math.BigDecimal;

public interface PaymentProcessor {
    void process(BigDecimal amount);
}

public class UpiProcessor implements PaymentProcessor {
    public void process(BigDecimal amount) {
        System.out.println("UPI payment: " + amount);
    }
}

public class CardProcessor implements PaymentProcessor {
    public void process(BigDecimal amount) {
        System.out.println("Card payment: " + amount);
    }
}

public class ProcessorFactory {
    public static PaymentProcessor create(String type) {
        return switch (type) {
            case "UPI" -> new UpiProcessor();
            case "CARD" -> new CardProcessor();
            default -> throw new IllegalArgumentException("Unknown: " + type);
        };
    }
}

The decision is "which one concrete class." Adding a new payment type is one class and one branch.

How does the Abstract Factory pattern work?

Abstract Factory has multiple product interfaces and a factory interface with one method per product. Each concrete factory produces a complete, consistent family.

JAVA
package com.bank.report;

// Product interfaces
public interface ReportHeader {
    String render();
}

public interface ReportFormatter {
    String format(String content);
}

public interface ReportFooter {
    String render();
}

// Abstract Factory interface
public interface DocumentFactory {
    ReportHeader createHeader();
    ReportFormatter createFormatter();
    ReportFooter createFooter();
}

// Regulatory family
public class RegulatoryHeader implements ReportHeader {
    public String render() { return "[REGULATORY FILING - RBI]"; }
}
public class RegulatoryFormatter implements ReportFormatter {
    public String format(String c) { return "FORMAL: " + c; }
}
public class RegulatoryFooter implements ReportFooter {
    public String render() { return "Certified by National Bank of India"; }
}
public class RegulatoryDocFactory implements DocumentFactory {
    public ReportHeader createHeader() { return new RegulatoryHeader(); }
    public ReportFormatter createFormatter() { return new RegulatoryFormatter(); }
    public ReportFooter createFooter() { return new RegulatoryFooter(); }
}

// Customer family
public class CustomerHeader implements ReportHeader {
    public String render() { return "Dear Valued Customer,"; }
}
public class CustomerFormatter implements ReportFormatter {
    public String format(String c) { return "Summary: " + c; }
}
public class CustomerFooter implements ReportFooter {
    public String render() { return "Thank you for banking with us!"; }
}
public class CustomerDocFactory implements DocumentFactory {
    public ReportHeader createHeader() { return new CustomerHeader(); }
    public ReportFormatter createFormatter() { return new CustomerFormatter(); }
    public ReportFooter createFooter() { return new CustomerFooter(); }
}

What is the structural difference?

| Aspect | Factory | Abstract Factory |
|---|---|---|
| Products | One product hierarchy | Multiple related product hierarchies |
| Question | Which one type? | Which matching family? |
| Output | One object | A set of consistent objects |
| Client depends on | Interface + factory | Abstract factory + abstract products |
| Swap | One product changes | Entire family changes at once |

How does the client use Abstract Factory?

The client depends only on the abstract factory and product interfaces. Switching the entire family is a one-line change.

JAVA
package com.bank.service;

public class ReportGenerator {
    private final DocumentFactory factory;

    public ReportGenerator(DocumentFactory factory) {
        this.factory = factory;
    }

    public void generate(String content) {
        System.out.println(factory.createHeader().render());
        System.out.println(factory.createFormatter().format(content));
        System.out.println(factory.createFooter().render());
    }
}
JAVA
package com.bank.demo;

public class AbstractFactoryDemo {
    public static void main(String[] args) {
        // Regulatory report
        ReportGenerator regGen = new ReportGenerator(new RegulatoryDocFactory());
        regGen.generate("Q4 compliance data");

        System.out.println();

        // Customer report – swap factory, everything changes
        ReportGenerator custGen = new ReportGenerator(new CustomerDocFactory());
        custGen.generate("Your account summary");
    }
}
TEXT
[REGULATORY FILING - RBI]
FORMAL: Q4 compliance data
Certified by National Bank of India

Dear Valued Customer,
Summary: Your account summary
Thank you for banking with us!

When do you use Factory vs Abstract Factory?

  • Use Factory when you have one product type whose concrete class varies: picking a settlement handler by trade type.
  • Use Abstract Factory when several products must vary together as a consistent set: a document with matching header, formatter, and footer.

What are common mistakes?

  • Using Abstract Factory when products do not need to match: a set of independent factory methods is simpler.
  • Mixing products from different families: a regulatory header with a customer footer produces an invalid document.

How do both patterns simplify in modern Java?

In modern Java, a Factory Method often collapses to a Map> lookup, and an Abstract Factory collapses to a record or interface returning lambdas. Sealed interfaces with pattern matching make the type hierarchy explicit and the factory switch expression exhaustive.

JAVA
package com.bank.pattern;

import java.math.BigDecimal;
import java.util.Map;
import java.util.function.Supplier;

public class ModernFactoryDemo {
    // Modern Factory: Map<String, Supplier>
    sealed interface FeeCalculator permits ProcessingFee, LateFee {
        BigDecimal calculate(BigDecimal principal);
    }
    record ProcessingFee() implements FeeCalculator {
        public BigDecimal calculate(BigDecimal p) { return p.multiply(new BigDecimal("0.01")); }
    }
    record LateFee() implements FeeCalculator {
        public BigDecimal calculate(BigDecimal p) { return p.multiply(new BigDecimal("0.02")); }
    }

    static final Map<String, Supplier<FeeCalculator>> FACTORY = Map.of(
        "PROCESSING", ProcessingFee::new,
        "LATE", LateFee::new
    );

    public static void main(String[] args) {
        FeeCalculator calc = FACTORY.get("PROCESSING").get();
        System.out.println("Fee: " + calc.calculate(new BigDecimal("100000")));
    }
}
TEXT
Expected output:
Fee: 1000.00

What should a senior engineer know?

  • Abstract Factory is more machinery than Factory. Only use it when family consistency genuinely matters.
  • In Spring, you can implement Abstract Factory by injecting different configuration profiles.
  • Abstract Factory is sometimes called "factory of factories" because each method inside it is its own factory method.
JAVA
// Senior tip: if products don't need to match,
// just use separate Factory methods
// HeaderFactory.create(type)
// FormatterFactory.create(type)
// Simpler and sufficient when consistency doesn't matter

Visual Overview

DIAGRAM
  Factory vs Abstract Factory
  ───────────────────────────

  Factory (one product):
  Client ──▶ ProcessorFactory.create("UPI") ──▶ UpiProcessor

  Abstract Factory (matching family):
  Client ──▶ RegulatoryDocFactory
                  │
                  ├──▶ createHeader()    ──▶ RegulatoryHeader
                  ├──▶ createFormatter() ──▶ RegulatoryFormatter
                  └──▶ createFooter()    ──▶ RegulatoryFooter

  Swap factory ──▶ CustomerDocFactory
                  │
                  ├──▶ createHeader()    ──▶ CustomerHeader
                  ├──▶ createFormatter() ──▶ CustomerFormatter
                  └──▶ createFooter()    ──▶ CustomerFooter

  Entire family swaps together – consistency guaranteed

Key Takeaway

The difference comes down to how many products the pattern creates and whether they must be consistent. Factory creates a single product from one hierarchy: it hides new behind a method and decides which concrete class. Abstract Factory creates a whole family of related products through a factory interface whose implementations each produce one complete, consistent set.

At National Bank of India, when a trade arrives and Pankaj needs the one correct settlement handler, that is a single-product decision and a plain Factory is enough. But when generating documents, a regulatory filing needs a regulatory header, a regulatory formatter, and a regulatory footer. Mixing a customer header with a regulatory formatter would produce an invalid document. That consistency requirement is exactly why the Abstract Factory exists.

The client depends only on the abstract factory and product interfaces. Rajesh's report-generation code takes a DocumentFactory and calls createHeader, createFormatter, and createFooter. Switching the entire family is a one-line change: hand it a different factory, and all products switch together.

The senior judgment is that Abstract Factory has more machinery, so Pankaj only uses it when family consistency genuinely matters. If products do not need to match, separate factory methods are simpler.

Remember one sentence: Factory picks one concrete product, Abstract Factory picks a matching family where all products must be consistent.

---

Share
Use ← → arrow keys to navigate