Abstract Factory Design Pattern
2 min readOct 26, 2024
The Abstract Factory design pattern is a creational pattern that provides an interface to create families of related or dependent objects without specifying their concrete classes. It’s useful when a system needs to work with multiple families of related products but shouldn’t depend on the specific classes of these products.
Key Concepts
- Abstract Factory Interface: Declares a set of methods for creating abstract products.
- Concrete Factory: Implements the abstract factory interface, creating concrete products.
- Abstract Product: Declares interfaces for a set of related products.
- Concrete Product: Implements the abstract product interface.
Example Use Case
Consider a UI theme where you need a different look for buttons and textboxes depending on the operating system (e.g., Windows, macOS).
- Abstract Factory:
GUIFactory
(interface with methods to create buttons and textboxes). - Concrete Factories:
WindowsFactory
,MacFactory
(implementGUIFactory
to create Windows or Mac-style buttons and textboxes). - Abstract Product:
Button
andTextBox
(define interfaces for buttons and textboxes). - Concrete Products:
WindowsButton
,MacButton
,WindowsTextBox
,MacTextBox
(implement abstract products).
// Abstract Products
interface Button {
void paint();
}
interface TextBox {
void render();
}
// Concrete Products for Windows
class WindowsButton implements Button {
public void paint() {
System.out.println("Rendering Windows Button");
}
}
class WindowsTextBox implements TextBox {
public void render() {
System.out.println("Rendering Windows TextBox");
}
}
// Concrete Products for Mac
class MacButton implements Button {
public void paint() {
System.out.println("Rendering Mac Button");
}
}
class MacTextBox implements TextBox {
public void render() {
System.out.println("Rendering Mac TextBox");
}
}
// Abstract Factory
interface GUIFactory {
Button createButton();
TextBox createTextBox();
}
// Concrete Factories
class WindowsFactory implements GUIFactory {
public Button createButton() {
return new WindowsButton();
}
public TextBox createTextBox() {
return new WindowsTextBox();
}
}
class MacFactory implements GUIFactory {
public Button createButton() {
return new MacButton();
}
public TextBox createTextBox() {
return new MacTextBox();
}
}
// Client
class Application {
private Button button;
private TextBox textBox;
public Application(GUIFactory factory) {
button = factory.createButton();
textBox = factory.createTextBox();
}
public void paint() {
button.paint();
textBox.render();
}
}
// Usage
public class Main {
public static void main(String[] args) {
GUIFactory factory;
// Depending on OS type or configuration
String osType = "Windows"; // This could be dynamically determined
if (osType.equals("Windows")) {
factory = new WindowsFactory();
} else {
factory = new MacFactory();
}
Application app = new Application(factory);
app.paint();
}
}
Benefits
- Isolation of Concrete Classes: The client only interacts with abstract interfaces.
- Easily Extendable: Adding a new family of products requires creating a new factory and products without changing existing code.
- Consistency: Ensures related products are used together.
When to Use
- When a system needs to be independent of how its products are created or composed.
- When the system should work with multiple families of related products.