1. Definition
The Abstract Factory Design Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
2. Problem Statement
Imagine you're developing a GUI library that should be compatible with multiple operating systems. Each OS has its own look and feel for elements like buttons, checkboxes, and windows. It's impractical to hardcode the creation of each UI element for each OS throughout your application.
3. Solution
Use the Abstract Factory pattern to define an interface for creating families of related objects, then implement concrete factories for each specific family (e.g., Windows UI elements, Linux UI elements, etc.).
4. Real-World Use Cases
1. GUI libraries where various OS or themes have different implementations of UI elements.
2. Toolkits and libraries that offer multiple variations of a set of functionalities, such as cloud provider resources or database connectors.
5. Implementation Steps
1. Define abstract product interfaces for each type of product.
2. Create an abstract factory interface with methods to produce those products.
3. Implement concrete factories for each family of products.
6. Implementation in Python
from abc import ABC, abstractmethod
# Abstract Products
class Button(ABC):
@abstractmethod
def render(self):
pass
class Checkbox(ABC):
@abstractmethod
def check(self):
pass
# Concrete Products: Windows
class WindowsButton(Button):
def render(self):
return "Windows Button Rendered"
class WindowsCheckbox(Checkbox):
def check(self):
return "Windows Checkbox Checked"
# Concrete Products: Linux
class LinuxButton(Button):
def render(self):
return "Linux Button Rendered"
class LinuxCheckbox(Checkbox):
def check(self):
return "Linux Checkbox Checked"
# Abstract Factory
class GUIFactory(ABC):
@abstractmethod
def create_button(self):
pass
@abstractmethod
def create_checkbox(self):
pass
# Concrete Factory: Windows
class WindowsFactory(GUIFactory):
def create_button(self):
return WindowsButton()
def create_checkbox(self):
return WindowsCheckbox()
# Concrete Factory: Linux
class LinuxFactory(GUIFactory):
def create_button(self):
return LinuxButton()
def create_checkbox(self):
return LinuxCheckbox()
# Client Code
factory = WindowsFactory()
button = factory.create_button()
checkbox = factory.create_checkbox()
print(button.render())
print(checkbox.check())
Output:
Windows Button Rendered Windows Checkbox Checked
Explanation:
1. We define abstract product interfaces (Button and Checkbox) that declare the desired methods.
2. Concrete implementations (WindowsButton, LinuxButton, etc.) provide the specific behavior for each family of products.
3. The GUIFactory abstract class sets the blueprint for methods that will produce products.
4. Concrete factories (WindowsFactory, LinuxFactory) implement these methods to produce products of their family.
5. The client code, instead of creating objects directly, uses the abstract factory to get products.
7. When to use?
The Abstract Factory Pattern is beneficial when:
1. The system needs to remain independent of how its objects are created, composed, and represented.
2. The system is configured with multiple families of objects.
3. You want to enforce that a set of related objects is always used together.