Abstract Factory
Abstract Factory produces a family of related objects designed to work together — not one product at a time.
Introduction
Abstract Factory produces a family of related objects designed to work together — not one product at a time. A MacFactory creates MacButton, MacScrollbar, MacWindow; a WindowsFactory creates the Windows family. In modern systems you'll see it wherever platform, tenant, or region determines a coordinated set: per-region payment + tax + currency, per-tenant UI theme + auth + storage.
The story
A fintech serving four regions needed payment, tax, currency, and notification implementations to match each country. Mixing US tax with EU payment rules caused a six-figure refund. A RegionFactory yielding the entire family per request made mismatched mixes a compile-time impossibility.
The business problem
Mixed-family construction causes invariant violations and costly incidents:
- Incompatible combos: EU tax rules with US payment processor — silent until refund event.
- Scattered coupling: each object type wired independently at call sites.
- Family growth pain: new region means editing every construction point.
- Review blindness: PR adds one member from wrong family — no type error.
The problem teams faced
Signals that Abstract Factory fits:
- Several object families exist; members must come from the same family.
- Consumer repeatedly couples to specific implementations across types.
- Adding a new family means editing many call sites.
- Runtime platform/tenant/region picks the whole coordinated set.
Understanding the topic
Intent: Provide an interface for creating families of related objects without specifying concrete classes.
- AbstractFactory — createPayment(), createTax(), createNotifier() — one interface.
- ConcreteFactory — EuFactory, UsFactory — each returns matching family members.
- Client — receives AbstractFactory once; never mixes families.
- Products — interfaces per role; concrete classes come in matched sets.
Internal architecture
Region factory interface:
interface RegionFactory {payment(): PaymentGatewaytax(): TaxCalculatorcurrency(): CurrencyFormatternotifier(): Notifier}class EuFactory implements RegionFactory { /* all EU impls */ }class UsFactory implements RegionFactory { /* all US impls */ }class CheckoutHandler {constructor(private region: RegionFactory) {}async execute(cart: Cart) {const total = this.region.tax().apply(cart)await this.region.payment().charge(total)await this.region.notifier().sendReceipt(cart)}}
Visual explanation
Three diagrams contrast families, Factory Method, and selection:
Informative example
Before / after — mixed families to coordinated factory:
// ❌ Mixed family — compiles, fails in productionconst payment = new StripeGateway() // USconst tax = new EuVatCalculator() // EU — wrong comboconst result = tax.apply(payment.charge(cart))// ✅ Factory guarantees family consistencyinterface CommerceFactory {payment(): PaymentGatewaytax(): TaxCalculator}class UsCommerceFactory implements CommerceFactory {payment = () => new StripeGateway(usConfig)tax = () => new UsSalesTaxCalculator()}class EuCommerceFactory implements CommerceFactory {payment = () => new AdyenGateway(euConfig)tax = () => new EuVatCalculator()}function checkout(factory: CommerceFactory, cart: Cart) {const charged = factory.payment().charge(cart)return factory.tax().apply(charged)}
Execution workflow
Identify family
List objects that must never mix (payment, tax, currency).
Real-world use
Cross-platform UI toolkits (Swing PLAF), JDBC driver families, cloud SDK environment bundles (AWS vs LocalStack factories for dev), theme systems (Material vs custom component sets), multi-tenant SaaS where tenant config selects storage + auth + billing as a set.
Production case study
Regional commerce factory:
- Scenario: Four regions, four object roles — 16 independent wiring points.
- Symptom: Six-figure refund from US tax + EU payment mismatch.
- Decision: RegionFactory injected per request at API gateway.
- Outcome: Wrong-family bugs eliminated; new region = one factory class.
- Metric: wiring call sites 16 → 1 per handler.
Trade-offs
- Pro: family consistency enforced by construction API.
- Pro: new family is additive — Open/Closed across roles.
- Con: heavy when only one product type varies.
- Con: interface explosion — N products × M families to maintain.
Decision framework
- Use when 2+ product roles must stay in the same family.
- Use when families map to tenant, region, platform, or environment.
- Avoid when only one object varies — Factory Method suffices.
- Avoid when families are theoretical — wait for second real family in git.
Best practices
- Inject factory at request boundary — resolve once per request.
- Keep product interfaces small — ISP applies inside families too.
- Name factories after the dimension that varies (Region, Tenant, Theme).
Anti-patterns to avoid
- Abstract Factory for one product — use Factory Method instead.
- God factory with 20 create methods — split by subdomain.
- Client still importing concrete products alongside factory.
Common mistakes
- Adding a new product role requires updating every concrete factory — plan for it.
- Over-abstracting before a second family exists in production.
- Process-wide factory when family varies per request.
Debugging tips
- Log factory class name at request start — trace wrong-region bugs.
- Integration test matrix: every factory × every handler path.
Optimization strategies
- Cache immutable factory products within request scope if create is expensive.
- Lazy-init heavy family members — not every request needs all roles.
Common misconceptions
- Abstract Factory ≠ Factory Method collection without guarantee. The family invariant is the point.
- Not every "Factory" class is Abstract Factory — need multiple coordinated product roles.
Advanced interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1IntermediateQuestionAbstract Factory vs Factory Method?+
Answer
Follow-up
2AdvancedQuestionWhen does adding a product role hurt?+
Answer
Follow-up
3IntermediateQuestionRequest-scoped vs singleton factory?+
Answer
Follow-up
4AdvancedQuestionHow prevent wrong-family bug at compile time?+
Answer
Follow-up
Summary
You can distinguish Abstract Factory from Factory Method, design region/tenant factories, and explain the refund incident. Tell the four-region fintech story — if you can do that, you own Abstract Factory.