Abstract Factory Pattern Tutorial from Scratch (2026)
The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. It is essentially a factory of factories, enabling platform-independent code by swapping entire product families at runtime.
This tutorial demonstrates Abstract Factory through GUI toolkit examples, cross-platform UI components, and database access layer implementations in Java and C++. You will learn how to create product families that work together while maintaining independence from concrete implementations.
Families of Products: GUI Toolkit Example
A classic use case for Abstract Factory is building cross-platform GUI components. Each platform (Windows, macOS, Linux) provides its own look-and-feel for buttons, checkboxes, and text fields. The Abstract Factory interface declares creation methods for each product type, and concrete factories implement platform-specific variants.
// Abstract product interfaces
interface Button {
void render();
void onClick();
}
interface Checkbox {
void render();
void toggle();
}
// Abstract factory interface
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// Concrete product families
class WinButton implements Button {
public void render() { System.out.println("Rendering Windows-style button"); }
public void onClick() { System.out.println("Windows button clicked"); }
}
class MacButton implements Button {
public void render() { System.out.println("Rendering macOS-style button"); }
public void onClick() { System.out.println("macOS button clicked"); }
}
class WinCheckbox implements Checkbox {
public void render() { System.out.println("Rendering Windows checkbox"); }
public void toggle() { System.out.println("Windows checkbox toggled"); }
}
class MacCheckbox implements Checkbox {
public void render() { System.out.println("Rendering macOS checkbox"); }
public void toggle() { System.out.println("macOS checkbox toggled"); }
}
// Concrete factories
class WinFactory implements GUIFactory {
public Button createButton() { return new WinButton(); }
public Checkbox createCheckbox() { return new WinCheckbox(); }
}
class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public Checkbox createCheckbox() { return new MacCheckbox(); }
}
Platform Independence via Abstract Factory
The client code receives a factory instance (e.g., from a configuration file or runtime detection) and uses it to create entire product families. This guarantees that products from the same family are used together, preventing mix-and-match errors like a Windows button with a macOS checkbox.
enum Platform { WINDOWS, MACOS, LINUX }
class Application {
private final Button button;
private final Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
public void render() {
button.render();
checkbox.render();
}
public static GUIFactory getFactory(Platform platform) {
return switch (platform) {
case WINDOWS -> new WinFactory();
case MACOS -> new MacFactory();
case LINUX -> new LinuxFactory();
};
}
public static void main(String[] args) {
Platform platform = Platform.valueOf(System.getProperty("os.name").toUpperCase());
Application app = new Application(getFactory(platform));
app.render();
}
}
Abstract Factory in C++ for Database Access
Abstract Factory is widely used in database abstraction layers. A DBFactory interface declares methods for creating connections, commands, and transactions. Concrete factories for MySQL, PostgreSQL, and SQLite each return driver-specific implementations, allowing the application to switch databases with minimal code changes.
class DBConnection {
public:
virtual void connect() = 0;
virtual void disconnect() = 0;
virtual ~DBConnection() = default;
};
class DBCommand {
public:
virtual void execute(const std::string& sql) = 0;
virtual ~DBCommand() = default;
};
class DBFactory {
public:
virtual std::unique_ptr createConnection() = 0;
virtual std::unique_ptr createCommand() = 0;
virtual ~DBFactory() = default;
};
class MySQLFactory : public DBFactory {
public:
std::unique_ptr createConnection() override {
return std::make_unique();
}
std::unique_ptr createCommand() override {
return std::make_unique();
}
};
Frequently Asked Questions
How is Abstract Factory different from Factory Method?
Factory Method creates a single product via inheritance, while Abstract Factory creates entire families of related products via composition. Abstract Factory uses multiple factory methods, one for each product type, and is typically implemented through object composition rather than inheritance.
When should I use Abstract Factory?
Use Abstract Factory when your system needs to be independent of how its products are created, when you work with multiple families of products, or when you must enforce that products from the same family are used together. It excels in cross-platform UI toolkits, database drivers, and theme engines.
How do I add a new product family to an Abstract Factory?
Create a new concrete factory class that implements the Abstract Factory interface, returning concrete products for the new family. The client code remains unchanged as it depends only on the abstract interfaces.
Does Abstract Factory add too much complexity for small projects?
Yes, Abstract Factory introduces significant boilerplate. For small projects, a simple factory or direct instantiation is more appropriate. Reserve Abstract Factory for systems that genuinely need to support multiple product families or require platform independence.
Originally published on Ayodhyyya. Last updated June 1, 2026.