Design Patterns - Creational
Abstract Factory Pattern
Provide an interface for creating families of related objects without specifying their concrete classes.
12 min readEssential
1What is Abstract Factory?
Real-World Analogy
Furniture Store
A furniture store offers different styles: Modern, Victorian, Art Deco. Each style has a complete family of products: chair, table, sofa. You ask for a style, and the store gives you matching furniture sets.
UI Theme
Your app supports Light and Dark themes. Each theme has matching buttons, inputs, cards. You switch themes and get a consistent familyof UI components.
Abstract Factory creates families of related objects without specifying their concrete classes. It ensures that products from one family are used together (e.g., Modern Chair + Modern Table, not Modern Chair + Victorian Table).
Abstract Factory Structure
interface
GUIFactory
createButton(), createInput()
LightThemeFactory
LightBtn
LightInput
DarkThemeFactory
DarkBtn
DarkInput
Each factory creates a complete family of compatible products
2Factory Method vs Abstract Factory
Factory Method
- Creates ONE product type
- Uses inheritance
- Single method
- Example: createNotification()
Abstract Factory
- Creates FAMILY of products
- Uses composition
- Multiple methods
- Example: createButton(), createInput()
When to Use Abstract Factory
Use when your code needs to work with various families of related products, but you do not want to depend on concrete classes. Perfect for: UI themes, cross-platform development (Windows/Mac/Linux), database abstraction.
3Implementation
UI Component Factory - creates matching buttons and inputs for different themes:
UI Theme Factory
// ========== Abstract Products ==========
interface Button {
void render();
void onClick();
}
interface Input {
void render();
String getValue();
}
// ========== Concrete Products - Light Theme ==========
class LightButton implements Button {
@Override
public void render() {
System.out.println("Rendering light button (white bg, black text)");
}
@Override
public void onClick() {
System.out.println("Light button clicked");
}
}
class LightInput implements Input {
@Override
public void render() {
System.out.println("Rendering light input (white bg, gray border)");
}
@Override
public String getValue() { return "light-input-value"; }
}
// ========== Concrete Products - Dark Theme ==========
class DarkButton implements Button {
@Override
public void render() {
System.out.println("Rendering dark button (dark bg, white text)");
}
@Override
public void onClick() {
System.out.println("Dark button clicked");
}
}
class DarkInput implements Input {
@Override
public void render() {
System.out.println("Rendering dark input (dark bg, light border)");
}
@Override
public String getValue() { return "dark-input-value"; }
}
// ========== Abstract Factory ==========
interface GUIFactory {
Button createButton();
Input createInput();
}
// ========== Concrete Factories ==========
class LightThemeFactory implements GUIFactory {
@Override
public Button createButton() {
return new LightButton();
}
@Override
public Input createInput() {
return new LightInput();
}
}
class DarkThemeFactory implements GUIFactory {
@Override
public Button createButton() {
return new DarkButton();
}
@Override
public Input createInput() {
return new DarkInput();
}
}
// ========== Client Code ==========
class Application {
private Button button;
private Input input;
// Client works with factory interface - no concrete classes
public Application(GUIFactory factory) {
this.button = factory.createButton();
this.input = factory.createInput();
}
public void render() {
button.render();
input.render();
}
}
// ========== Usage ==========
public class Main {
public static void main(String[] args) {
// Choose factory based on config/user preference
String theme = "dark";
GUIFactory factory;
if (theme.equals("dark")) {
factory = new DarkThemeFactory();
} else {
factory = new LightThemeFactory();
}
// Application works with any factory
Application app = new Application(factory);
app.render();
// Output for dark theme:
// Rendering dark button (dark bg, white text)
// Rendering dark input (dark bg, light border)
}
}Output (Dark Theme):
Rendering dark button (dark bg, white text) Rendering dark input (dark bg, light border)
4Real-World Examples
Java AWTToolkit creates native UI components for each OS
javax.xmlDocumentBuilderFactory creates XML parsers
DatabaseConnectionFactory creates DB-specific connections
Game DevTerrainFactory creates matching terrain, enemies, items per level
UI LibrariesTheme providers in Material UI, Chakra UI
5Interview Questions
What is the Abstract Factory pattern?
Abstract Factory provides an interface for creating families of related objects without specifying concrete classes. Each concrete factory creates a complete family of products. Example: LightThemeFactory creates LightButton + LightInput that match each other visually.
When would you use Abstract Factory over Factory Method?
Use Abstract Factory when: 1) You have multiple related products that must be used together, 2) You want to ensure compatibility within a product family, 3) You're building cross-platform or themed applications. Use Factory Method for single products.
What are the advantages and disadvantages?
Advantages: Ensures compatibility of products, isolates concrete classes, easy to swap product families, follows Open/Closed Principle. Disadvantages: Can be complex with many products, adding new product types requires changing all factories.
6Key Takeaways
1Abstract Factory creates families of related products.
2Ensures compatibility within product families.
3Each concrete factory creates a complete set of matching products.
4Useful for: themes, cross-platform apps, database abstraction.
5More complex than Factory Method but handles related products.
6Adding new products requires changing all factories (limitation).