Abstract Factory Pattern
🎯 Explain Like I'm 5...
Imagine you have two different furniture factories: one makes Modern furniture and one makes Victorian furniture!
🏭 The Magic of Factories:
Modern Furniture Factory:
- • Makes a sleek, simple chair 🪑
- • Makes a glass table with metal legs 🔲
Victorian Furniture Factory:
- • Makes a fancy chair with carvings 👑
- • Makes a wooden table with decorations 🎨
🌟 The Key Idea:
Both factories know how to make a chair and a table, but each makes them in their own style! You can ask any factory for furniture, and you'll get matching pieces!
🚀 Why Is This Useful?
- • All your furniture matches - no mixing modern chairs with Victorian tables!
- • You can easily switch from modern to Victorian style by changing the factory!
- • Adding a new style (like 'Art Deco') is easy - just make a new factory!
🎯 Pattern Purpose
The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. It ensures that products created together belong to the same family and are compatible with each other.
📋 When to Use Abstract Factory
- ✅Your system needs to work with multiple families of related products
- ✅You want to ensure products from the same family are used together
- ✅You want to provide a library of products revealing only interfaces, not implementations
- ✅You need to configure your system with one of multiple families of products
🌍 Real-World Examples
- 🖥️Cross-Platform UI Toolkits: Windows vs macOS buttons, scrollbars, and dialogs
- 🗄️Database Connectors: MySQL vs PostgreSQL connections, statements, and result sets
- 🎨Theme Systems: Light vs Dark theme colors, fonts, and icons
- 📄Document Formats: PDF vs Word document elements and formatters
💻 Java Implementations
Example 1: GUI Framework (Windows vs Mac)
Creating cross-platform user interface components that look native on each operating system.
// Abstract Product: Button// This interface defines what all buttons must be able to dopublic interface Button { void paint(); // Draw the button on screen void onClick(); // Handle button click}// Abstract Product: Checkbox// This interface defines what all checkboxes must be able to dopublic interface Checkbox { void paint(); // Draw the checkbox on screen void onCheck(); // Handle checkbox check/uncheck}// Abstract Product: Scrollbar// This interface defines what all scrollbars must be able to dopublic interface Scrollbar { void paint(); // Draw the scrollbar on screen void onScroll(); // Handle scrolling action}// Concrete Product: Windows Button// This is how a button looks and behaves on Windowspublic class WindowsButton implements Button { @Override public void paint() { System.out.println("Rendering a button in Windows style"); System.out.println(" [ Windows Button ]"); } @Override public void onClick() { System.out.println("Windows button clicked!"); }}// Concrete Product: Windows Checkbox// This is how a checkbox looks and behaves on Windowspublic class WindowsCheckbox implements Checkbox { @Override public void paint() { System.out.println("Rendering a checkbox in Windows style"); System.out.println(" [ ] Windows Checkbox"); } @Override public void onCheck() { System.out.println("Windows checkbox toggled!"); }}// Concrete Product: Windows Scrollbar// This is how a scrollbar looks and behaves on Windowspublic class WindowsScrollbar implements Scrollbar { @Override public void paint() { System.out.println("Rendering a scrollbar in Windows style"); System.out.println(" [|||] Windows Scrollbar"); } @Override public void onScroll() { System.out.println("Windows scrollbar scrolled!"); }}// Concrete Product: Mac Button// This is how a button looks and behaves on macOSpublic class MacButton implements Button { @Override public void paint() { System.out.println("Rendering a button in Mac style"); System.out.println(" ( Mac Button )"); } @Override public void onClick() { System.out.println("Mac button clicked!"); }}// Concrete Product: Mac Checkbox// This is how a checkbox looks and behaves on macOSpublic class MacCheckbox implements Checkbox { @Override public void paint() { System.out.println("Rendering a checkbox in Mac style"); System.out.println(" ☐ Mac Checkbox"); } @Override public void onCheck() { System.out.println("Mac checkbox toggled!"); }}// Concrete Product: Mac Scrollbar// This is how a scrollbar looks and behaves on macOSpublic class MacScrollbar implements Scrollbar { @Override public void paint() { System.out.println("Rendering a scrollbar in Mac style"); System.out.println(" [:::] Mac Scrollbar"); } @Override public void onScroll() { System.out.println("Mac scrollbar scrolled!"); }}// Abstract Factory: GUIFactory// This interface defines how to create a family of related GUI components// Each concrete factory will create components that work well togetherpublic interface GUIFactory { Button createButton(); // Create a button for this platform Checkbox createCheckbox(); // Create a checkbox for this platform Scrollbar createScrollbar(); // Create a scrollbar for this platform}// Concrete Factory: Windows Factory// This factory creates all Windows-style components// All components created by this factory look and work like Windowspublic class WindowsFactory implements GUIFactory { @Override public Button createButton() { return new WindowsButton(); } @Override public Checkbox createCheckbox() { return new WindowsCheckbox(); } @Override public Scrollbar createScrollbar() { return new WindowsScrollbar(); }}// Concrete Factory: Mac Factory// This factory creates all Mac-style components// All components created by this factory look and work like macOSpublic class MacFactory implements GUIFactory { @Override public Button createButton() { return new MacButton(); } @Override public Checkbox createCheckbox() { return new MacCheckbox(); } @Override public Scrollbar createScrollbar() { return new MacScrollbar(); }}// Client Code: Application// This application works with any GUI factory// It doesn't know if it's creating Windows or Mac componentspublic class Application { private Button button; private Checkbox checkbox; private Scrollbar scrollbar; // Constructor receives a factory - could be Windows or Mac! public Application(GUIFactory factory) { button = factory.createButton(); checkbox = factory.createCheckbox(); scrollbar = factory.createScrollbar(); } // Paint all UI components public void paint() { button.paint(); checkbox.paint(); scrollbar.paint(); } // Handle user interaction public void interact() { button.onClick(); checkbox.onCheck(); scrollbar.onScroll(); }}// Demo: Using the GUI Abstract Factorypublic class GUIDemo { public static void main(String[] args) { // Determine which operating system we're on String osName = System.getProperty("os.name").toLowerCase(); GUIFactory factory; // Choose the appropriate factory based on OS if (osName.contains("windows")) { System.out.println("Creating Windows GUI...\n"); factory = new WindowsFactory(); } else if (osName.contains("mac")) { System.out.println("Creating Mac GUI...\n"); factory = new MacFactory(); } else { System.out.println("Creating default (Windows) GUI...\n"); factory = new WindowsFactory(); } // Create application with the chosen factory Application app = new Application(factory); System.out.println("Painting UI components:"); app.paint(); System.out.println("\nSimulating user interaction:"); app.interact(); System.out.println("\n--- Demonstrating Mac GUI ---\n"); // We can easily switch to Mac style by using MacFactory Application macApp = new Application(new MacFactory()); macApp.paint(); macApp.interact(); }}Example 2: Theme System (Light vs Dark)
Building a theme system where all UI components match the selected theme.
// Abstract Product: Color scheme// Defines the color interface for theme componentspublic interface Color { String getPrimaryColor(); // Main color for the theme String getSecondaryColor(); // Accent color String getBackgroundColor(); // Background color String getTextColor(); // Text color}// Abstract Product: Font settings// Defines the font interface for theme componentspublic interface Font { String getFontFamily(); // Font name (Arial, Times, etc.) int getFontSize(); // Size in pixels String getFontWeight(); // normal, bold, etc.}// Abstract Product: Icon set// Defines the icon interface for theme componentspublic interface Icon { String getHomeIcon(); // Home icon representation String getSettingsIcon(); // Settings icon representation String getProfileIcon(); // Profile icon representation}// Concrete Product: Light theme colors// Bright, easy-on-the-eyes colors for daytime usepublic class LightColor implements Color { @Override public String getPrimaryColor() { return "#2196F3"; // Blue } @Override public String getSecondaryColor() { return "#FFC107"; // Amber } @Override public String getBackgroundColor() { return "#FFFFFF"; // White } @Override public String getTextColor() { return "#000000"; // Black }}// Concrete Product: Light theme font// Regular weight fonts for light backgroundspublic class LightFont implements Font { @Override public String getFontFamily() { return "Roboto"; } @Override public int getFontSize() { return 16; } @Override public String getFontWeight() { return "normal"; // Regular weight for light theme }}// Concrete Product: Light theme icons// Outlined icons that work well on light backgroundspublic class LightIcon implements Icon { @Override public String getHomeIcon() { return "🏠 (outlined)"; // Simple outlined home } @Override public String getSettingsIcon() { return "⚙️ (outlined)"; // Simple outlined gear } @Override public String getProfileIcon() { return "👤 (outlined)"; // Simple outlined person }}// Concrete Product: Dark theme colors// Dark, comfortable colors for nighttime usepublic class DarkColor implements Color { @Override public String getPrimaryColor() { return "#BB86FC"; // Purple } @Override public String getSecondaryColor() { return "#03DAC6"; // Teal } @Override public String getBackgroundColor() { return "#121212"; // Almost black } @Override public String getTextColor() { return "#FFFFFF"; // White }}// Concrete Product: Dark theme font// Slightly lighter weight fonts for dark backgroundspublic class DarkFont implements Font { @Override public String getFontFamily() { return "Roboto"; } @Override public int getFontSize() { return 16; } @Override public String getFontWeight() { return "300"; // Light weight for dark theme (easier to read) }}// Concrete Product: Dark theme icons// Filled icons that stand out on dark backgroundspublic class DarkIcon implements Icon { @Override public String getHomeIcon() { return "🏠 (filled)"; // Solid filled home } @Override public String getSettingsIcon() { return "⚙️ (filled)"; // Solid filled gear } @Override public String getProfileIcon() { return "👤 (filled)"; // Solid filled person }}// Abstract Factory: Theme Factory// This interface defines how to create a complete theme// Each theme has colors, fonts, and icons that work togetherpublic interface ThemeFactory { Color createColor(); // Create color scheme for this theme Font createFont(); // Create font settings for this theme Icon createIcon(); // Create icon set for this theme}// Concrete Factory: Light Theme Factory// Creates all components for a light, daytime theme// All components are designed to work togetherpublic class LightThemeFactory implements ThemeFactory { @Override public Color createColor() { return new LightColor(); } @Override public Font createFont() { return new LightFont(); } @Override public Icon createIcon() { return new LightIcon(); }}// Concrete Factory: Dark Theme Factory// Creates all components for a dark, nighttime theme// All components are designed to work togetherpublic class DarkThemeFactory implements ThemeFactory { @Override public Color createColor() { return new DarkColor(); } @Override public Font createFont() { return new DarkFont(); } @Override public Icon createIcon() { return new DarkIcon(); }}// Client Code: UI Renderer// This class renders the UI using theme components// It works with any theme without knowing which one it ispublic class UIRenderer { private Color color; private Font font; private Icon icon; // Constructor receives a theme factory public UIRenderer(ThemeFactory factory) { this.color = factory.createColor(); this.font = factory.createFont(); this.icon = factory.createIcon(); } // Render the user interface with current theme public void render() { System.out.println("=== Rendering UI ==="); System.out.println("Background: " + color.getBackgroundColor()); System.out.println("Text: " + color.getTextColor()); System.out.println("Primary: " + color.getPrimaryColor()); System.out.println("Secondary: " + color.getSecondaryColor()); System.out.println(); System.out.println("Font: " + font.getFontFamily() + " " + font.getFontSize() + "px " + font.getFontWeight()); System.out.println(); System.out.println("Icons:"); System.out.println(" Home: " + icon.getHomeIcon()); System.out.println(" Settings: " + icon.getSettingsIcon()); System.out.println(" Profile: " + icon.getProfileIcon()); System.out.println("===================\n"); }}// Demo: Using the Theme Abstract Factorypublic class ThemeDemo { public static void main(String[] args) { // Simulate user preference or time of day boolean isDarkMode = true; System.out.println("Theme System Demo\n"); // Create appropriate theme factory based on preference ThemeFactory factory; if (isDarkMode) { System.out.println("User prefers dark mode\n"); factory = new DarkThemeFactory(); } else { System.out.println("User prefers light mode\n"); factory = new LightThemeFactory(); } // Create UI renderer with chosen theme UIRenderer renderer = new UIRenderer(factory); renderer.render(); // Switching themes is easy - just create a new renderer with different factory System.out.println("\n--- Switching to Light Theme ---\n"); UIRenderer lightRenderer = new UIRenderer(new LightThemeFactory()); lightRenderer.render(); System.out.println("\n--- Switching back to Dark Theme ---\n"); UIRenderer darkRenderer = new UIRenderer(new DarkThemeFactory()); darkRenderer.render(); }}Example 3: Vehicle Parts Factory (Car vs Truck)
Manufacturing vehicle parts where each vehicle type gets compatible components.
// Abstract Product: Engine// All vehicles need an engine, but different types of enginespublic interface Engine { void start(); // Start the engine void stop(); // Stop the engine int getHorsepower(); // Get engine power String getFuelType(); // Get fuel type (gasoline, diesel, etc.)}// Abstract Product: Tire// All vehicles need tires, but different sizes and typespublic interface Tire { int getDiameter(); // Tire size in inches String getTerrainType(); // Road, off-road, etc. void inflate(); // Add air to tire void checkPressure(); // Check tire pressure}// Abstract Product: Chassis// The frame/body of the vehiclepublic interface Chassis { String getMaterial(); // Steel, aluminum, etc. int getWeightCapacity(); // Maximum load in kg void inspect(); // Check chassis condition}// Concrete Product: Car Engine// Smaller, efficient engine for passenger carspublic class CarEngine implements Engine { @Override public void start() { System.out.println("Car engine starting with smooth purr..."); } @Override public void stop() { System.out.println("Car engine stopping quietly..."); } @Override public int getHorsepower() { return 150; // Moderate power for city driving } @Override public String getFuelType() { return "Gasoline"; }}// Concrete Product: Car Tire// Standard road tires for smooth highway drivingpublic class CarTire implements Tire { @Override public int getDiameter() { return 17; // Inches - standard car tire size } @Override public String getTerrainType() { return "Paved roads"; } @Override public void inflate() { System.out.println("Inflating car tire to 32 PSI..."); } @Override public void checkPressure() { System.out.println("Car tire pressure is normal (32 PSI)"); }}// Concrete Product: Car Chassis// Lightweight frame for passenger comfortpublic class CarChassis implements Chassis { @Override public String getMaterial() { return "Aluminum alloy"; // Lightweight for fuel efficiency } @Override public int getWeightCapacity() { return 500; // kg - passengers and luggage } @Override public void inspect() { System.out.println("Inspecting car chassis: Lightweight, no rust"); }}// Concrete Product: Truck Engine// Powerful, heavy-duty engine for hauling cargopublic class TruckEngine implements Engine { @Override public void start() { System.out.println("Truck engine starting with deep rumble..."); } @Override public void stop() { System.out.println("Truck engine stopping with vibration..."); } @Override public int getHorsepower() { return 400; // High power for heavy loads } @Override public String getFuelType() { return "Diesel"; }}// Concrete Product: Truck Tire// Large, durable tires for heavy loadspublic class TruckTire implements Tire { @Override public int getDiameter() { return 24; // Inches - large truck tire } @Override public String getTerrainType() { return "Highway and off-road"; } @Override public void inflate() { System.out.println("Inflating truck tire to 80 PSI..."); } @Override public void checkPressure() { System.out.println("Truck tire pressure is normal (80 PSI)"); }}// Concrete Product: Truck Chassis// Heavy-duty frame for cargo and durabilitypublic class TruckChassis implements Chassis { @Override public String getMaterial() { return "Reinforced steel"; // Strong for heavy loads } @Override public int getWeightCapacity() { return 5000; // kg - heavy cargo capacity } @Override public void inspect() { System.out.println("Inspecting truck chassis: Heavy-duty, very strong"); }}// Abstract Factory: Vehicle Parts Factory// This interface defines how to create a complete set of vehicle parts// Each vehicle type gets compatible parts designed to work togetherpublic interface VehicleFactory { Engine createEngine(); // Create engine for this vehicle type Tire createTire(); // Create tire for this vehicle type Chassis createChassis(); // Create chassis for this vehicle type}// Concrete Factory: Car Parts Factory// Creates all parts needed to build a passenger car// All parts are designed to work together efficientlypublic class CarFactory implements VehicleFactory { @Override public Engine createEngine() { return new CarEngine(); } @Override public Tire createTire() { return new CarTire(); } @Override public Chassis createChassis() { return new CarChassis(); }}// Concrete Factory: Truck Parts Factory// Creates all parts needed to build a cargo truck// All parts are designed for heavy-duty performancepublic class TruckFactory implements VehicleFactory { @Override public Engine createEngine() { return new TruckEngine(); } @Override public Tire createTire() { return new TruckTire(); } @Override public Chassis createChassis() { return new TruckChassis(); }}// Client Code: Vehicle Assembly// This class assembles a vehicle using parts from a factory// It doesn't care if it's building a car or truckpublic class Vehicle { private Engine engine; private Tire tire; private Chassis chassis; private String type; // Constructor receives a factory and vehicle type public Vehicle(VehicleFactory factory, String type) { this.type = type; this.engine = factory.createEngine(); this.tire = factory.createTire(); this.chassis = factory.createChassis(); } // Display vehicle specifications public void showSpecs() { System.out.println("=== " + type + " Specifications ==="); System.out.println(); System.out.println("Engine:"); System.out.println(" Horsepower: " + engine.getHorsepower() + " HP"); System.out.println(" Fuel Type: " + engine.getFuelType()); System.out.println(); System.out.println("Tires:"); System.out.println(" Diameter: " + tire.getDiameter() + " inches"); System.out.println(" Terrain: " + tire.getTerrainType()); System.out.println(); System.out.println("Chassis:"); System.out.println(" Material: " + chassis.getMaterial()); System.out.println(" Weight Capacity: " + chassis.getWeightCapacity() + " kg"); System.out.println("========================\n"); } // Test all vehicle components public void test() { System.out.println("Testing " + type + "...\n"); engine.start(); tire.inflate(); tire.checkPressure(); chassis.inspect(); engine.stop(); System.out.println(); }}// Demo: Using the Vehicle Abstract Factorypublic class VehicleDemo { public static void main(String[] args) { System.out.println("Vehicle Manufacturing System\n"); System.out.println("============================\n"); // Build a car using CarFactory System.out.println("Building a Car...\n"); VehicleFactory carFactory = new CarFactory(); Vehicle car = new Vehicle(carFactory, "Passenger Car"); car.showSpecs(); car.test(); System.out.println("\n" + "=".repeat(50) + "\n"); // Build a truck using TruckFactory System.out.println("Building a Truck...\n"); VehicleFactory truckFactory = new TruckFactory(); Vehicle truck = new Vehicle(truckFactory, "Cargo Truck"); truck.showSpecs(); truck.test(); System.out.println("\n" + "=".repeat(50) + "\n"); // Key advantage: All parts are compatible System.out.println("Key Benefit: All parts from the same factory are compatible!"); System.out.println("Car parts work together, truck parts work together."); System.out.println("No mixing car engines with truck chassis!"); }}🔄 Abstract Factory vs Factory Method
These patterns are related but serve different purposes:
Factory Method:
- • Creates ONE type of product
- • Uses inheritance (subclasses decide which class to instantiate)
- • Example: Different types of pizzas
Abstract Factory:
- • Creates FAMILIES of related products
- • Uses composition (object delegates creation to factory object)
- • Example: Complete furniture sets (Modern set: chair + table + sofa)
🔑 Key Points to Remember
- 1️⃣Abstract Factory creates families of related objects
- 2️⃣Products from one factory are compatible with each other
- 3️⃣Each concrete factory produces a complete set of products
- 4️⃣Client code works with factories and products through abstract interfaces
- 5️⃣Easy to add new product families, hard to add new product types
- 6️⃣Ensures consistency among products created by the same factory
💪 Practice Scenarios
- • Create a Restaurant Menu Factory (Italian vs Chinese cuisine with appetizer, main course, dessert)
- • Implement a Game Character Factory (Warrior vs Mage with weapon, armor, skill)
- • Build a Report Generator Factory (PDF vs Excel with header, content, footer)
- • Design a Cloud Provider Factory (AWS vs Azure with storage, compute, database services)
- • Develop a Mobile UI Factory (iOS vs Android with button, input field, navigation bar)