DEV Community

Cover image for Understanding the Abstract Factory Design Pattern
Diego Brener
Diego Brener

Posted on

Understanding the Abstract Factory Design Pattern

Abstract Factory Design Pattern UML

Understanding the Abstract Factory Design Pattern

Problem

The Abstract Factory pattern addresses the need to create families of related or dependent objects without specifying their concrete classes. This is useful when a system needs to be independent of how its objects are created, composed, and represented, ensuring that products created together are compatible.

Solution

The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. This interface defines a set of methods for creating abstract products, which concrete factory classes implement to create concrete products. This promotes loose coupling by ensuring that client code interacts with the factory interface rather than concrete classes directly.

Pros and Cons

Pros

  • Decouples Client Code: Allows client code to work with an interface for object creation, promoting flexibility and maintainability.
  • Promotes Consistency: Ensures that products created by the factories are compatible with each other.
  • Supports Open-Closed Principle: New product families can be added without modifying existing client code, adhering to the Open-Closed Principle.

Cons

  • Complexity: Introduces additional complexity with the introduction of multiple factory and product classes.
  • Requires Subclassing: Each product family requires its own factory, potentially leading to a proliferation of classes in the codebase.
  • Not Suitable for Simple Cases: Overuse of the Abstract Factory pattern in simple scenarios can lead to unnecessary abstraction and complexity.

Example of Real-World Application

A practical example of the Abstract Factory pattern is in a UI toolkit that supports multiple themes. Depending on the selected theme (e.g., Windows, MacOS), a corresponding factory creates UI components (buttons, checkboxes) with the appropriate appearance and behavior.

Example Code in Java

Abstract Factory pattern in code


java
// Abstract Product A
public interface Button {
    void paint();
}

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

// Concrete Product A1
public class WindowsButton implements Button {
    @Override
    public void paint() {
        System.out.println("Rendering a button in Windows style");
    }
}

// Concrete Product B1
public class WindowsCheckbox implements Checkbox {
    @Override
    public void paint() {
        System.out.println("Rendering a checkbox in Windows style");
    }
}

// Concrete Product A2
public class MacOSButton implements Button {
    @Override
    public void paint() {
        System.out.println("Rendering a button in MacOS style");
    }
}

// Concrete Product B2
public class MacOSCheckbox implements Checkbox {
    @Override
    public void paint() {
        System.out.println("Rendering a checkbox in MacOS style");
    }
}

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

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

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

// Concrete Factory 2
public class MacOSFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacOSButton();
    }

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

// Client code
public class Application {
    private Button button;
    private Checkbox checkbox;

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

    public void paint() {
        button.paint();
        checkbox.paint();
    }

    public static void main(String[] args) {
        GUIFactory factory;
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.contains("mac")) {
            factory = new MacOSFactory();
        } else {
            factory = new WindowsFactory();
        }
        Application app = new Application(factory);
        app.paint();
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)