Abstract Factory Pattern
The Abstract Factory Pattern
The Abstract Factory pattern provides an interface for creating families of related objects without specifying their concrete classes. Where the Factory Method creates one product, the Abstract Factory creates whole product families designed to work together.
Why Families of Objects?
Consider UI themes. A dark theme must use dark-styled buttons, menus, and scrollbars everywhere. Mixing a dark button with a light scrollbar breaks the design. The Abstract Factory guarantees that every product produced by a factory belongs to the same consistent family.
+---------------------------+
| ThemeFactory |
| (abstract factory) |
+---------------------------+
| | |
> > > create* methods
+----------+ +------+ +---------+
| Button | | Menu | |Scrollbar| (product interfaces)
+----------+ +------+ +---------+
| | |
> > > implemented by
+----------+ +------+ +---------+
|DarkButton| |Dark | |DarkScrl |
|LightButton| |Light| |LightScrl|
+-----------+ +-----+ +--------+
Each concrete factory supplies one product of each type, so the whole set stays visually consistent.
Step 1: Product Interfaces
Define the abstract interfaces every family must implement.
public interface Button {
void render();
}
public interface Menu {
void display();
}
public interface Scrollbar {
void draw();
}
These interfaces are the kinds of objects the factory produces.
Step 2: The Abstract Factory and Implementations
The factory interface declares one creation method per product type. Each concrete factory returns a matching family.
public interface ThemeFactory {
Button createButton();
Menu createMenu();
Scrollbar createScrollbar();
}
public class DarkThemeFactory implements ThemeFactory {
public Button createButton() { return new DarkButton(); }
public Menu createMenu() { return new DarkMenu(); }
public Scrollbar createScrollbar() { return new DarkScrollbar(); }
}
public class LightThemeFactory implements ThemeFactory {
public Button createButton() { return new LightButton(); }
public Menu createMenu() { return new LightMenu(); }
public Scrollbar createScrollbar() { return new LightScrollbar(); }
}
DarkButton, DarkMenu, and DarkScrollbar are all in the dark family; the light factory returns only light-family objects.
Step 3: Consuming the Factory
The application builds its interface purely through the factory abstraction.
public class Application {
private final Button button;
private final Menu menu;
private final Scrollbar scrollbar;
public Application(ThemeFactory factory) {
this.button = factory.createButton();
this.menu = factory.createMenu();
this.scrollbar = factory.createScrollbar();
}
public void buildUI() {
button.render();
menu.display();
scrollbar.draw();
}
}
// Switching themes requires NO change to Application
Application dark = new Application(new DarkThemeFactory());
Application light = new Application(new LightThemeFactory());
Walkthrough: Application receives any ThemeFactory. It calls createButton, createMenu, and createScrollbar and stores whatever comes back. Because it only knows the interfaces, switching from DarkThemeFactory to LightThemeFactory changes nothing in Application - you simply pass a different factory at startup.
Real-World Use Cases
JDBC is the classic example: the driver manager is an Abstract Factory whose factory returns Connection, Statement, and ResultSet objects consistent with one database vendor. Swing and JavaFX use theme factories for consistent component creation. Cross-platform toolkits use it to produce native-looking widgets on each operating system.
Key Points
- Abstract Factory creates families of related objects without naming concrete classes.
- Each factory implementation produces one consistent family, such as a theme.
- Consumer code depends only on abstract interfaces and can switch families freely.
- Critical when product consistency across a family matters.
- Used by JDBC drivers, UI frameworks, and cross-platform toolkits.