Abstract Factory Pattern

Introduction

The Abstract Factory pattern provides an interface for creating families of related objects without specifying their concrete classes. While the Factory Method creates one product, the Abstract Factory creates an entire suite of products that are designed to work together. This is the pattern you reach for when your system needs to support multiple variants of a product family.

The Problem

Imagine building a cross-platform UI toolkit that must render components differently on Windows, macOS, and Linux. Each platform needs its own buttons, text inputs, checkboxes, and dialogs — but they must be internally consistent. A Windows button should never accidentally appear alongside a macOS checkbox. If you create each component independently, you risk mixing platform-specific implementations in ways that break the user experience.

The Solution

The Abstract Factory defines an interface with creation methods for each component type (button, text input, checkbox). Each platform provides a concrete factory that produces the matching component family. The application code works exclusively through the abstract interfaces — it never knows which platform-specific classes it is using. Switching platforms means swapping one factory for another.

Key Principle

Ensure product compatibility by constraining creation to families. The abstract factory guarantees that all objects produced by a single factory are designed to work together, eliminating cross-family mixing at the structural level.

Java Example

This example creates a UI component factory system that produces consistent component families for different themes (Material and iOS).

// Abstract products
public interface Button {
    String render();
    String onClick(String action);
}

public interface TextField {
    String render(String placeholder);
    String getValue();
}

public interface Checkbox {
    String render(String label);
    boolean isChecked();
}

// Material Design implementations
public class MaterialButton implements Button {
    @Override
    public String render() {
        return "[Material Button with ripple effect and elevation]";
    }
    @Override
    public String onClick(String action) {
        return "Material ripple animation -> " + action;
    }
}

public class MaterialTextField implements TextField {
    private String value = "";
    @Override
    public String render(String placeholder) {
        return "[Material TextField: floating label '" + placeholder + "']";
    }
    @Override
    public String getValue() { return value; }
}

public class MaterialCheckbox implements Checkbox {
    private boolean checked = false;
    @Override
    public String render(String label) {
        return "[Material Checkbox: " + label + " with animated checkmark]";
    }
    @Override
    public boolean isChecked() { return checked; }
}

// iOS implementations
public class IOSButton implements Button {
    @Override
    public String render() {
        return "[iOS Button with haptic feedback and rounded corners]";
    }
    @Override
    public String onClick(String action) {
        return "iOS haptic tap -> " + action;
    }
}

public class IOSTextField implements TextField {
    private String value = "";
    @Override
    public String render(String placeholder) {
        return "[iOS TextField: inline placeholder '" + placeholder + "']";
    }
    @Override
    public String getValue() { return value; }
}

public class IOSCheckbox implements Checkbox {
    private boolean checked = false;
    @Override
    public String render(String label) {
        return "[iOS Toggle Switch: " + label + " with smooth slide]";
    }
    @Override
    public boolean isChecked() { return checked; }
}

// Abstract factory interface
public interface UIComponentFactory {
    Button createButton();
    TextField createTextField();
    Checkbox createCheckbox();
}

// Concrete factories
public class MaterialUIFactory implements UIComponentFactory {
    @Override
    public Button createButton() { return new MaterialButton(); }
    @Override
    public TextField createTextField() { return new MaterialTextField(); }
    @Override
    public Checkbox createCheckbox() { return new MaterialCheckbox(); }
}

public class IOSUIFactory implements UIComponentFactory {
    @Override
    public Button createButton() { return new IOSButton(); }
    @Override
    public TextField createTextField() { return new IOSTextField(); }
    @Override
    public Checkbox createCheckbox() { return new IOSCheckbox(); }
}

// Client code works with abstractions only
public class LoginForm {
    private final Button submitButton;
    private final TextField usernameField;
    private final TextField passwordField;
    private final Checkbox rememberMe;

    public LoginForm(UIComponentFactory factory) {
        this.submitButton = factory.createButton();
        this.usernameField = factory.createTextField();
        this.passwordField = factory.createTextField();
        this.rememberMe = factory.createCheckbox();
    }

    public void render() {
        System.out.println("=== Login Form ===");
        System.out.println(usernameField.render("Username"));
        System.out.println(passwordField.render("Password"));
        System.out.println(rememberMe.render("Remember me"));
        System.out.println(submitButton.render());
        System.out.println(submitButton.onClick("submit login"));
    }

    public static void main(String[] args) {
        // Switch theme by swapping the factory
        String theme = "material";

        UIComponentFactory factory = theme.equals("ios")
            ? new IOSUIFactory()
            : new MaterialUIFactory();

        LoginForm form = new LoginForm(factory);
        form.render();
    }
}

Python Example

The same UI component factory system in Python, using abstract base classes.

from abc import ABC, abstractmethod


# Abstract products
class Button(ABC):
    @abstractmethod
    def render(self) -> str:
        pass

    @abstractmethod
    def on_click(self, action: str) -> str:
        pass


class TextField(ABC):
    @abstractmethod
    def render(self, placeholder: str) -> str:
        pass

    @abstractmethod
    def get_value(self) -> str:
        pass


class Checkbox(ABC):
    @abstractmethod
    def render(self, label: str) -> str:
        pass

    @abstractmethod
    def is_checked(self) -> bool:
        pass


# Material Design implementations
class MaterialButton(Button):
    def render(self) -> str:
        return "[Material Button with ripple effect and elevation]"

    def on_click(self, action: str) -> str:
        return f"Material ripple animation -> {action}"


class MaterialTextField(TextField):
    def __init__(self):
        self._value = ""

    def render(self, placeholder: str) -> str:
        return f"[Material TextField: floating label '{placeholder}']"

    def get_value(self) -> str:
        return self._value


class MaterialCheckbox(Checkbox):
    def __init__(self):
        self._checked = False

    def render(self, label: str) -> str:
        return f"[Material Checkbox: {label} with animated checkmark]"

    def is_checked(self) -> bool:
        return self._checked


# iOS implementations
class IOSButton(Button):
    def render(self) -> str:
        return "[iOS Button with haptic feedback and rounded corners]"

    def on_click(self, action: str) -> str:
        return f"iOS haptic tap -> {action}"


class IOSTextField(TextField):
    def __init__(self):
        self._value = ""

    def render(self, placeholder: str) -> str:
        return f"[iOS TextField: inline placeholder '{placeholder}']"

    def get_value(self) -> str:
        return self._value


class IOSCheckbox(Checkbox):
    def __init__(self):
        self._checked = False

    def render(self, label: str) -> str:
        return f"[iOS Toggle Switch: {label} with smooth slide]"

    def is_checked(self) -> bool:
        return self._checked


# Abstract factory
class UIComponentFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button:
        pass

    @abstractmethod
    def create_text_field(self) -> TextField:
        pass

    @abstractmethod
    def create_checkbox(self) -> Checkbox:
        pass


# Concrete factories
class MaterialUIFactory(UIComponentFactory):
    def create_button(self) -> Button:
        return MaterialButton()

    def create_text_field(self) -> TextField:
        return MaterialTextField()

    def create_checkbox(self) -> Checkbox:
        return MaterialCheckbox()


class IOSUIFactory(UIComponentFactory):
    def create_button(self) -> Button:
        return IOSButton()

    def create_text_field(self) -> TextField:
        return IOSTextField()

    def create_checkbox(self) -> Checkbox:
        return IOSCheckbox()


# Client code works with abstractions only
class LoginForm:
    def __init__(self, factory: UIComponentFactory):
        self.submit_button = factory.create_button()
        self.username_field = factory.create_text_field()
        self.password_field = factory.create_text_field()
        self.remember_me = factory.create_checkbox()

    def render(self):
        print("=== Login Form ===")
        print(self.username_field.render("Username"))
        print(self.password_field.render("Password"))
        print(self.remember_me.render("Remember me"))
        print(self.submit_button.render())
        print(self.submit_button.on_click("submit login"))


# Usage
if __name__ == "__main__":
    theme = "material"

    factory = IOSUIFactory() if theme == "ios" else MaterialUIFactory()

    form = LoginForm(factory)
    form.render()

When to Use

  • Product families — when your system produces groups of related objects (UI components, database connectors, serialization handlers) that must remain consistent with each other.
  • Platform abstraction — when you need to support multiple platforms or environments (Windows/macOS/Linux, Material/iOS, AWS/GCP/Azure) with the same application code.
  • Theme/skin systems — when users can switch between visual themes and all components must update together to maintain a cohesive look.
  • Testing with fake services — when you want to swap an entire family of real service clients with in-memory fakes for integration testing.

Real-World Usage

  • Java AWT/Swing — the LookAndFeel system uses abstract factories to produce platform-consistent UI components (buttons, scrollbars, menus).
  • javax.xml.parsersDocumentBuilderFactory and SAXParserFactory produce families of XML parsing components.
  • Hibernate — dialect-specific factories produce SQL generators, type mappers, and schema validators tailored to each database engine.
  • Django REST Framework — renderer and parser factories produce families of serialization components (JSON, XML, YAML) that work together consistently.



Subscribe To Our Newsletter
You will receive our latest post and tutorial.
Thank you for subscribing!

required
required


Leave a Reply

Your email address will not be published. Required fields are marked *