# Abstract Factory

## Problem

You need to create **families of related objects** (e.g., Button + Checkbox + Menu) that must
be consistent with each other. Mixing a Windows Button with a Mac Checkbox would break the UI.
A single Factory Method can't enforce cross-product consistency.

## Solution

Define an **Abstract Factory** interface with a creation method per product type.
Each concrete factory produces an entire family of compatible products.

```
┌───────────────────┐
│   UIFactory       │ (abstract)
│  +createButton()  │
│  +createCheckbox()│
└────────┬──────────┘
         │
   ┌─────┴──────┐
   │            │
┌──┴──────┐ ┌──┴──────┐
│WinFactory│ │MacFactory│
└──┬──────┘ └──┬──────┘
   │            │
   │ creates    │ creates
   ▼            ▼
WinButton    MacButton
WinCheckbox  MacCheckbox
```

## When to Use

- You have multiple families of related products (themes, OS targets, DB backends).
- Products within a family must be used together — mixing is a bug.
- You want to swap entire families at runtime via configuration.

## When to Avoid

- You only have one product type — Factory Method is simpler.
- Families rarely change and there are only two variants — the abstraction overhead isn't worth it.
- Products within a family don't interact — independent factories suffice.

## Pseudocode

```
interface Button:
    method render()

interface Checkbox:
    method render()

interface UIFactory:
    method createButton() -> Button
    method createCheckbox() -> Checkbox

class WinButton implements Button:
    method render(): print("[Windows Button]")

class WinCheckbox implements Checkbox:
    method render(): print("[Windows Checkbox]")

class MacButton implements Button:
    method render(): print("[Mac Button]")

class MacCheckbox implements Checkbox:
    method render(): print("[Mac Checkbox]")

class WindowsFactory implements UIFactory:
    method createButton(): return new WinButton()
    method createCheckbox(): return new WinCheckbox()

class MacFactory implements UIFactory:
    method createButton(): return new MacButton()
    method createCheckbox(): return new MacCheckbox()

function buildUI(factory: UIFactory):
    button = factory.createButton()
    checkbox = factory.createCheckbox()
    button.render()
    checkbox.render()

// Usage
factory = if os == "windows" then WindowsFactory() else MacFactory()
buildUI(factory)
```

## Python

```python
"""Abstract Factory — UI toolkit example."""

from abc import ABC, abstractmethod


# --- Abstract products ---

class Button(ABC):
    @abstractmethod
    def render(self) -> str: ...

class Checkbox(ABC):
    @abstractmethod
    def render(self) -> str: ...


# --- Concrete products: Windows ---

class WinButton(Button):
    def render(self) -> str:
        return "[Windows Button]"

class WinCheckbox(Checkbox):
    def render(self) -> str:
        return "[Windows Checkbox]"


# --- Concrete products: Mac ---

class MacButton(Button):
    def render(self) -> str:
        return "[Mac Button]"

class MacCheckbox(Checkbox):
    def render(self) -> str:
        return "[Mac Checkbox]"


# --- Abstract factory ---

class UIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button: ...
    @abstractmethod
    def create_checkbox(self) -> Checkbox: ...


# --- Concrete factories ---

class WindowsFactory(UIFactory):
    def create_button(self) -> Button:
        return WinButton()
    def create_checkbox(self) -> Checkbox:
        return WinCheckbox()

class MacFactory(UIFactory):
    def create_button(self) -> Button:
        return MacButton()
    def create_checkbox(self) -> Checkbox:
        return MacCheckbox()


# --- Client code ---

def build_ui(factory: UIFactory) -> None:
    button = factory.create_button()
    checkbox = factory.create_checkbox()
    print(f"  Button:   {button.render()}")
    print(f"  Checkbox: {checkbox.render()}")


if __name__ == "__main__":
    for name, factory in [("Windows", WindowsFactory()), ("Mac", MacFactory())]:
        print(f"{name} theme:")
        build_ui(factory)
    print("--- Abstract factory demo complete ---")
```

## Go

```go
// abstract_factory.go — UI toolkit example
package main

import "fmt"

// --- Abstract products ---

type Button interface {
	Render() string
}

type Checkbox interface {
	Render() string
}

// --- Concrete products: Windows ---

type WinButton struct{}
func (w *WinButton) Render() string { return "[Windows Button]" }

type WinCheckbox struct{}
func (w *WinCheckbox) Render() string { return "[Windows Checkbox]" }

// --- Concrete products: Mac ---

type MacButton struct{}
func (m *MacButton) Render() string { return "[Mac Button]" }

type MacCheckbox struct{}
func (m *MacCheckbox) Render() string { return "[Mac Checkbox]" }

// --- Abstract factory ---

type UIFactory interface {
	CreateButton() Button
	CreateCheckbox() Checkbox
}

// --- Concrete factories ---

type WindowsFactory struct{}
func (f *WindowsFactory) CreateButton() Button    { return &WinButton{} }
func (f *WindowsFactory) CreateCheckbox() Checkbox { return &WinCheckbox{} }

type MacFactory struct{}
func (f *MacFactory) CreateButton() Button    { return &MacButton{} }
func (f *MacFactory) CreateCheckbox() Checkbox { return &MacCheckbox{} }

// --- Client code ---

func buildUI(factory UIFactory) {
	button := factory.CreateButton()
	checkbox := factory.CreateCheckbox()
	fmt.Printf("  Button:   %s\n", button.Render())
	fmt.Printf("  Checkbox: %s\n", checkbox.Render())
}

func main() {
	factories := map[string]UIFactory{
		"Windows": &WindowsFactory{},
		"Mac":     &MacFactory{},
	}
	for name, factory := range factories {
		fmt.Printf("%s theme:\n", name)
		buildUI(factory)
	}
	fmt.Println("--- Abstract factory demo complete ---")
}
```

## JavaScript

```javascript
// abstract_factory.js — UI toolkit example

// --- Concrete products: Windows ---

class WinButton {
  render() { return "[Windows Button]"; }
}

class WinCheckbox {
  render() { return "[Windows Checkbox]"; }
}

// --- Concrete products: Mac ---

class MacButton {
  render() { return "[Mac Button]"; }
}

class MacCheckbox {
  render() { return "[Mac Checkbox]"; }
}

// --- Concrete factories ---

class WindowsFactory {
  createButton()   { return new WinButton(); }
  createCheckbox() { return new WinCheckbox(); }
}

class MacFactory {
  createButton()   { return new MacButton(); }
  createCheckbox() { return new MacCheckbox(); }
}

// --- Client code ---

function buildUI(factory) {
  const button = factory.createButton();
  const checkbox = factory.createCheckbox();
  console.log(`  Button:   ${button.render()}`);
  console.log(`  Checkbox: ${checkbox.render()}`);
}

// --- Demo ---
for (const [name, factory] of [
  ["Windows", new WindowsFactory()],
  ["Mac", new MacFactory()],
]) {
  console.log(`${name} theme:`);
  buildUI(factory);
}
console.log("--- Abstract factory demo complete ---");
```

## Related Patterns

- **Factory Method** — abstract factory uses factory methods internally; use factory method when only one product family is needed.
- **Builder** — builder constructs a complex object step by step; abstract factory produces families of related objects in one call.
- **Prototype** — prototype can be used inside an abstract factory to create products by cloning prototypes.
- **Bridge** — abstract factory is often used with bridge to create platform-specific implementations of an abstraction.
