DEV Community

Aleson França
Aleson França

Posted on

Abstract Factory: Create Object With Elegance

Have you ever needed to create several related objects, like UI components for different themes (light/dark), databases, or API drivers? If yes, you probably noticed that keeping your code flexible and easy to maintain can be hard. This is where the Abstract Factory pattern helps.

In this post, I will show you how to use Abstract Factory in PHP, with simple examples and tips from real experience.


The Problem

Imagine you are building a user interface that can be shown in light or dark theme. Each theme has its own button and checkbox. Without a pattern, your code might look like this:

if ($theme === 'dark') {
    $button = new DarkButton();
    $checkbox = new DarkCheckbox();
} else {
    $button = new LightButton();
    $checkbox = new LightCheckbox();
}
Enter fullscreen mode Exit fullscreen mode

This works, but it is hard to maintain. If you want to add a new theme, you need to change your code in many places. Also, you might mix components from different themes by mistake.

Solution: Abstract Factory

The Abstract Factory pattern solves this problem by creating an interface to produce families of related objects, without depending on their concrete classes.

Define Interfaces

interface Button {
    public function render(): void;
}

interface Checkbox {
    public function render(): void;
}
Enter fullscreen mode Exit fullscreen mode

Implement the concrete class

class LightButton implements Button {
    public function render(): void {
        echo "Light Button<br>";
    }
}

class DarkButton implements Button {
    public function render(): void {
        echo "Dark Button<br>";
    }
}

class LightCheckbox implements Checkbox {
    public function render(): void {
        echo "Light Checkbox<br>";
    }
}

class DarkCheckbox implements Checkbox {
    public function render(): void {
        echo "Dark Checkbox<br>";
    }
}
Enter fullscreen mode Exit fullscreen mode

Create the abstract factory

interface UIFactory {
    public function createButton(): Button;
    public function createCheckbox(): Checkbox;
}
Enter fullscreen mode Exit fullscreen mode

Implement concrete factories

class LightFactory implements UIFactory {
    public function createButton(): Button {
        return new LightButton();
    }
    public function createCheckbox(): Checkbox {
        return new LightCheckbox();
    }
}

class DarkFactory implements UIFactory {
    public function createButton(): Button {
        return new DarkButton();
    }
    public function createCheckbox(): Checkbox {
        return new DarkCheckbox();
    }
}
Enter fullscreen mode Exit fullscreen mode

How to use implementation

function renderUI(UIFactory $factory) {
    $button = $factory->createButton();
    $checkbox = $factory->createCheckbox();
    $button->render();
    $checkbox->render();
}


$theme = 'dark';
$factory = $theme === 'dark' ? new DarkFactory() : new LightFactory();
renderUI($factory);
Enter fullscreen mode Exit fullscreen mode

Advantages

  • Decoupling: The client code does not need to know which concrete classes are used.
  • Consistency: It makes sure all objects created belong to the same family(theme)
  • Easy to extend: To add a new theme, just create a new factory and new concrete products.

Conclusion

Abstract Factory can look complex at first, but it is an elegant solution for real problems of maintenance and scalability. In big projects, it really helps to organize your code.

Top comments (0)