Suggest an editImprove this articleRefine the answer for “Abstract factory pattern”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Abstract Factory** is a creational design pattern that creates families of related objects through a shared interface, without exposing concrete classes. ```typescript interface GUIFactory { createButton(): Button; createCheckbox(): Checkbox; } class WinFactory implements GUIFactory { createButton() { return new WinButton(); } createCheckbox() { return new WinCheckbox(); } } ``` **Key point:** one factory = one consistent family. Client code picks the factory once and all products match automatically.Shown above the full answer for quick recall.Answer (EN)Image**Abstract Factory** is a creational design pattern that provides an interface for creating families of related objects without specifying their concrete classes. ## Theory ### TL;DR - Like a car factory blueprint that produces matching sets: engine + tires + seats, all fitting together. Swap the blueprint, get a different but still consistent set. - Main difference from Factory Method: Abstract Factory creates a whole family of products, Factory Method creates one. - Use when your app needs swappable product families: UI themes, OS-specific widgets, dev/prod database drivers. - One factory = one consistent family. Client code never accidentally mixes Windows buttons with Mac checkboxes. ### Quick example ```typescript interface Button { render(): void; } interface Checkbox { render(): void; } interface GUIFactory { createButton(): Button; createCheckbox(): Checkbox; } class WindowsFactory implements GUIFactory { createButton(): Button { return { render: () => console.log('WindowsButton') }; } createCheckbox(): Checkbox { return { render: () => console.log('WindowsCheckbox') }; } } // Pick one factory, get a consistent family const factory: GUIFactory = new WindowsFactory(); factory.createButton().render(); // WindowsButton factory.createCheckbox().render(); // WindowsCheckbox ``` One factory call locks you into a consistent family. No accidental mixing of parts from different families. ### Key difference from Factory Method Factory Method is one method that creates one product, typically overridden in a subclass. Abstract Factory is an interface with multiple methods, each producing a different product from the same family. Client code picks a factory once and all subsequent product calls stay consistent. That consistency is the whole point. ### When to use - Multiple products that must match each other: light/dark UI themes where button, input, and modal all need the same style. - Runtime config swaps the family: dev uses an in-memory database driver, prod uses PostgreSQL. One factory swap changes all related objects. - Framework-level abstraction: OS-specific widgets. Java AWT does exactly this with `Toolkit.getDefaultToolkit()`. - If you only have one product variant, Factory Method is enough. Abstract Factory adds classes; make sure the tradeoff is worth it. ### How the runtime handles it In TypeScript and Java, the factory reference is abstract at compile time. The runtime resolves actual method calls through vtables, dispatching to the concrete factory based on which instance you assigned. No compile-time binding to concrete product classes. Swap the factory instance via config or dependency injection and all products change without touching client code. ### Common mistakes **Treating it like a single-product factory** ```typescript // Wrong: separate factories per product risk mixing families class ButtonFactory { createButton(): Button { /* windows */ } } class CheckboxFactory { createCheckbox(): Checkbox { /* mac */ } } // Nothing stops mixing Windows button with Mac checkbox ``` Group all family members under one factory. The family constraint only holds when all products come from the same place. **Instantiating concrete classes in client code** ```typescript // Wrong: client knows the concrete class const btn = new WindowsButton(); // Breaks the abstraction entirely // Right: always through the factory const btn = factory.createButton(); ``` The moment client code references `WindowsButton`, swapping families requires touching that code. The whole point of the pattern is avoiding this. **Over-abstracting small apps** Ten classes for two buttons is a YAGNI violation. Abstract Factory pays off when you have two or more families with two or more products each. For a single toggle between variants, a simple conditional works fine and is far easier to read. **Singleton factory caching stale state** A module-level singleton factory can cache the wrong family after a config reload or hot restart. I saw this bite a team in Node.js: one worker's theme factory cached a dark theme, and it leaked into subsequent requests after a config change. Fresh instance per request or context fixed it. If your factory carries config state, don't create it once at startup and share it everywhere. ### Real-world usage - Java AWT: `Toolkit.getDefaultToolkit()` returns an OS-family factory that creates `WindowsButton`, `MotifMenu`, and similar widgets without client code knowing which platform it runs on. - React Native: platform-specific UI kits serve `iOSButton` and `AndroidButton` from the same interface. - Kubernetes client: factory pattern for cluster configs, in-cluster vs out-of-cluster, so the same app code works inside and outside a cluster. - gRPC: channel factories switch between HTTP/2 and Unix socket families depending on the deployment context. ### Follow-up questions **Q:** What is the difference between Abstract Factory and Factory Method? **A:** Factory Method is one method that creates one product, usually overridden in a subclass. Abstract Factory is an interface with multiple methods, each creating a different product from the same family. Factory Method = one product. Abstract Factory = one family. **Q:** When does Abstract Factory hurt performance? **A:** Factory instantiation itself is cheap. The issue is creating a new factory instance on every call instead of reusing it. Cache the factory as a singleton where the family does not change per request. **Q:** How is Abstract Factory different from the Prototype pattern? **A:** Prototype clones existing objects. Abstract Factory creates fresh instances through factory methods. Prototype is useful when creation is expensive and new objects are similar to existing ones. Abstract Factory is about family consistency, not cloning. **Q:** Can Abstract Factory cause circular dependency issues? **A:** Yes. If factory A creates object B, and B internally tries to create something back through A, you get a cycle. The fix is to let the factory own the full lifecycle and sequence creation internally. The pattern where `createDatabase()` calls `this.createLogger()` inside the factory is the safe approach: factory sequences creation, products do not hold a reference back to the factory. **Q:** How do you evolve Abstract Factory to support plugins without changing client code? **A:** Use a factory registry with dynamic loading. In Java, `ServiceLoader` discovers factory implementations at runtime. Client calls `AbstractFactory.getInstance(config)`, and the registry resolves which concrete factory to load. Adding a plugin means dropping in a new factory class with no client code changes. "Add an if/else" is the junior answer. The senior answer is a registry with dynamic resolution. ## Examples ### Basic: GUI factory for Windows and Mac ```typescript interface Button { render(): void; } interface Checkbox { toggle(): void; } interface GUIFactory { createButton(): Button; createCheckbox(): Checkbox; } class MacFactory implements GUIFactory { createButton(): Button { return { render: () => console.log('Mac button') }; } createCheckbox(): Checkbox { return { toggle: () => console.log('Mac checkbox') }; } } class WinFactory implements GUIFactory { createButton(): Button { return { render: () => console.log('Win button') }; } createCheckbox(): Checkbox { return { toggle: () => console.log('Win checkbox') }; } } function renderUI(factory: GUIFactory) { factory.createButton().render(); factory.createCheckbox().toggle(); } renderUI(new MacFactory()); // Mac button, Mac checkbox renderUI(new WinFactory()); // Win button, Win checkbox ``` `renderUI` does not know or care which platform it targets. Swap the factory, swap the entire UI family. This is the pattern at its simplest. ### Intermediate: React theme factory with OS preference detection ```typescript interface ThemeButton { render(): JSX.Element; } interface ThemeInput { render(): JSX.Element; } interface ThemeFactory { createButton(): ThemeButton; createInput(): ThemeInput; } class DarkThemeFactory implements ThemeFactory { createButton(): ThemeButton { return { render: () => <button style={{ background: 'black', color: 'white' }}>Click</button> }; } createInput(): ThemeInput { return { render: () => <input style={{ background: '#333', color: 'white' }} /> }; } } class LightThemeFactory implements ThemeFactory { createButton(): ThemeButton { return { render: () => <button style={{ background: 'white', color: 'black' }}>Click</button> }; } createInput(): ThemeInput { return { render: () => <input style={{ background: '#fff', color: 'black' }} /> }; } } const App: React.FC = () => { const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; const factory: ThemeFactory = isDark ? new DarkThemeFactory() : new LightThemeFactory(); return ( <div> {factory.createButton().render()} {factory.createInput().render()} </div> ); }; ``` Factory choice happens once at component initialization. All themed elements come from the same factory, so they always match. No manual coordination required. ### Advanced: Dependency injection with lifecycle control ```typescript interface Logger { log(msg: string): void; } interface Database { query(sql: string): string; } interface AppFactory { createLogger(): Logger; createDatabase(): Database; } class ProdFactory implements AppFactory { createLogger(): Logger { return { log: (msg) => console.log(`[PROD] ${msg}`) }; } createDatabase(): Database { const logger = this.createLogger(); // Factory sequences creation internally return { query: (sql) => { logger.log(`Executing: ${sql}`); return 'results'; } }; } } const factory = new ProdFactory(); const db = factory.createDatabase(); db.query('SELECT *'); // [PROD] Executing: SELECT * ``` `Database` needs `Logger`, but there is no circular dependency because the factory controls the sequence. If you wired these manually outside the factory, swapping `ProdFactory` for a `DevFactory` would require touching all the wiring code. This is where Abstract Factory earns its place in real projects.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.