Advanced Java September 20 ,2025

Abstract Factory Design Pattern in Java

Introduction

The Abstract Factory Pattern is another powerful creational design pattern. While the Factory Method Pattern focuses on creating one product at a time, the Abstract Factory Pattern is about creating families of related objects without specifying their concrete classes.

In simpler words:

  • A Factory Method creates one product.
  • An Abstract Factory creates a set of products that are meant to be used together.

This pattern is especially useful when your system needs to be platform-independent or when it must support multiple product variants.

Problem Statement

Imagine you are designing a Cross-Platform UI Library that must support two environments:

  1. Windows
  2. Mac

Each environment has its own UI look and feel. For example:

  • A Windows application has Windows-style Buttons and Windows-style Checkboxes.
  • A Mac application has Mac-style Buttons and Mac-style Checkboxes.

Now, the problem:

  • You need a way to create buttons and checkboxes, but ensure that they match the environment (Windows or Mac).
  • If you mix them accidentally (e.g., Windows Button + Mac Checkbox), the UI will look inconsistent.

If you directly hardcode object creation like this:

if (os.equals("Windows")) {
    Button btn = new WindowsButton();
    Checkbox chk = new MacCheckbox(); // mistake: mixed!
}

…it becomes messy, error-prone, and violates loose coupling.

Solution with Abstract Factory Pattern

The Abstract Factory Pattern groups related factories into one “super factory” (an abstract factory).

  • Define abstract products (e.g., Button, Checkbox).
  • Define an abstract factory that declares creation methods for these products.
  • Implement concrete factories for each environment (Windows, Mac).
  • Clients only depend on the abstract factory, never on concrete classes.

This way, the client always gets a consistent family of products.

Implementation in Java

Step 1: Abstract Product Interfaces

// Product A
public interface Button {
    void render();
}

// Product B
public interface Checkbox {
    void render();
}

Step 2: Concrete Products (Windows Family)

public class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("Rendering a Windows-style button");
    }
}

public class WindowsCheckbox implements Checkbox {
    @Override
    public void render() {
        System.out.println("Rendering a Windows-style checkbox");
    }
}

Step 3: Concrete Products (Mac Family)

public class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("Rendering a Mac-style button");
    }
}

public class MacCheckbox implements Checkbox {
    @Override
    public void render() {
        System.out.println("Rendering a Mac-style checkbox");
    }
}

Step 4: Abstract Factory

public interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

Step 5: Concrete Factories

public class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

public class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

Step 6: Client Code

public class Application {
    private Button button;
    private Checkbox checkbox;

    public Application(GUIFactory factory) {
        button = factory.createButton();
        checkbox = factory.createCheckbox();
    }

    public void renderUI() {
        button.render();
        checkbox.render();
    }

    public static void main(String[] args) {
        // Decide the environment at runtime
        String os = "Mac"; // could come from config, system property, etc.

        GUIFactory factory;
        if (os.equalsIgnoreCase("Windows")) {
            factory = new WindowsFactory();
        } else {
            factory = new MacFactory();
        }

        Application app = new Application(factory);
        app.renderUI();
    }
}

Output (if Mac is selected)

Rendering a Mac-style button
Rendering a Mac-style checkbox

Output (if Windows is selected)

Rendering a Windows-style button
Rendering a Windows-style checkbox

Notice how:

  • The client (Application) doesn’t know or care about WindowsButton or MacCheckbox.
  • The factory guarantees that both Button and Checkbox belong to the same family.

Real-World Analogy

Think of a furniture shop.

  • You don’t want to mix a Victorian chair with a Modern sofa — they should match.
  • A Victorian Furniture Factory creates Victorian-style products (chairs, sofas, tables).
  • A Modern Furniture Factory creates modern-style products.

When you pick a style, the factory ensures consistency.

Advantages of Abstract Factory Pattern

  1. Ensures Consistency: Creates families of related objects that work well together.
  2. Loose Coupling: Client code depends only on interfaces, not concrete classes.
  3. Open/Closed Principle: Adding a new product family (LinuxFactory) doesn’t affect existing code.
  4. Runtime Flexibility: Choose product family at runtime (Windows, Mac).

Disadvantages

  1. Complexity: More classes and interfaces compared to Factory Method.
  2. Difficult to Extend Products Individually: Adding a new product type (e.g., Slider) requires changes in all factories.

When to Use

  • When your system needs to be independent of product creation.
  • When you want to enforce that a family of related products is used together.
  • When supporting multiple product variants (themes, platforms, UI kits).

Conclusion

The Abstract Factory Pattern builds upon the Factory Method by dealing with groups of related objects. It ensures consistency across product families, making it ideal for cross-platform applications, theming engines, or plugin-based architectures.

In our example, we built a Cross-Platform UI Library where the client chooses between Windows and Mac factories, and gets a consistent look-and-feel.

Next, we will study the Singleton Design Pattern — a pattern that ensures a class has only one instance and provides a global point of access to it.

 

Sanjiv
0

You must logged in to post comments.

Get In Touch

G06, Kristal Olivine Bellandur near Bangalore Central Mall, Bangalore Karnataka, 560103

+91-8076082435

techiefreak87@gmail.com