Design patterns are reusable templates that help us to solve software design problems using best practices. In that way, they allow us to build applications using code that is easier to maintain, understand and test.

Processing…
Success!

What is this pattern used for?

It provides an interface to create families of related or dependent objects without specifying their concrete classes.

For example, imagine we want to create an app for iOS. The iPhone has two different visual aspects: light mode and dark mode. If the user uses light mode, we will have to show light visual components (buttons, navigation bars, etc), and if they use dark mode, dark components.

But that means that every time we create a visual element in our code we will have to review what visual mode is being used and choose the right component. This creates three problems:

  • If a third visual mode is introduced, we will have to change the code in all locations where a component is created.
  • We mix application logic with logic that describes how to create the visual components.
  • We may accidentally mix light buttons with dark navigation bars, for example.

By using the Abstract Factory pattern we will ensure that the application code remains separate from the code of the visual components. That is, the application will simply create a button or a navigation bar, and the factory will produce the appropriate components according to the visual mode used. On the other hand, the factory used will only produce elements of one visual aspect, preventing us from mixing them. And finally, if a third visual mode appears, we just need to change the line of code where the appropriate factory is chosen.

How does it work?

The following diagram describes the classes involved:

Diagram of the Abstract factory pattern.

The application will use a component factory that will take care of generating the appropriate buttons and navigation bars, without the application having to worry about the details.
To achieve that, we create three abstract classes, which are those with which the application will have contact, rather than their concrete implementations:

class ComponentFactory(ABC):
    @abstractmethod
    def create_button(self):
        pass    
    @abstractmethod
    def create_navbar(self):
        pass

class Button(ABC):
    @abstractmethod
    def render(self):
        pass

class Navbar(ABC):
    @abstractmethod
    def render(self):
        pass

A factory is a class that can create objects of a certain family. An abstract factory is a template for creating factories. Thanks to our abstract factory (ComponentFactory) we will be able to create two different factories, one to produce the elements of the light theme and another one for the dark theme.

class LightThemeFactory(ComponentFactory):
    def create_button(self):
        return LightButton()    
    def create_navbar(self):
        return LightNavbar()

class LightButton(Button):
    def render(self):
        ...

class LightNavbar(Navbar):
    def render(self):
        ...

class DarkThemeFactory(ComponentFactory):
    def create_button(self):
        return DarkButton()

def create_navbar(self):
        return DarkNavbar()

class DarkButton(Button):
    def render(self):
        ...

class DarkNavbar(Navbar):
    def render(self):
        ...

As you can see, both factories are able to create buttons and navigation bars of a particular type, which extend the abstract classes Button and Navbar.
In this way, when starting the application we simply create the appropriate factory:

if theme == "dark":
    component_factory = DarkThemeFactory()
elif theme == "light":
    component_factory = LightThemeFactory()
else:
    raise NotImplementedError(f"This visual mode doesn't exist")

And to create components, we simply do:

button = componentfactory.create_button()
navbar = componentfactory.create_navbar()

Benefits

  • The application does not care about the component details.
  • It encapsulates the creation of objects in a class (the factory) instead of creating them directly.
  • The factory can be changed while the app executes by changing only a few lines of code.
  • The app can be tested independently of its visual appearance.

Escape Velocity Labs

You can find all our articles, courses, and tutorials on our website:
https://www.evlabs.io

Write A Comment