Abstract Factory Pattern - Commonly Used for UI Themes or Objects

CK CK 3788 
Created at
Updated at  
1,467 0 0

The Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. It separates the creation of objects from their usage, allowing for easier switching between different object families (e.g., different UI themes or database systems) simply by changing the factory implementation without modifying client code that uses those objects. This promotes loose coupling and enhances flexibility in software design.


The Abstract Factory design pattern is a creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. Think of it as a factory of factories. Instead of creating individual objects directly, you use an abstract factory to get families of related objects. This decouples the client code from the concrete classes being created, making the system more flexible and easier to maintain.

 

Abstract Factory Pattern - Commonly Used for UI Themes or Objects


Here's a breakdown:

  • Intent: Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
  • Problem: When you have multiple families of related objects (e.g., UI widgets for different operating systems – Windows, macOS, Linux), creating these objects directly in your client code tightly couples it to the specific implementations. Changes to the implementation (e.g., adding a new OS) require modifying the client code.
  • Solution: Introduce an abstract factory. This factory defines an interface for creating the various objects in a family. Concrete factories implement this interface, creating the specific objects for their family. The client code interacts only with the abstract factory interface, eliminating direct dependence on concrete classes.

Key Participants:

  • Abstract Factory: Declares an interface for operations that create abstract product objects.
  • Concrete Factory: Implements the operations to create concrete product objects.
  • Abstract Product: Declares an interface for a type of product object.
  • Concrete Product: Implements the Abstract Product interface. Each concrete factory creates a family of concrete products.
  • Client: Uses only interfaces declared by abstract classes.

Example:
Imagine creating UI widgets. You might have buttons, text fields, and scroll bars. An abstract factory could define methods like createButton(), createTextField(), and createScrollBar(). Concrete factories (e.g., WindowsFactory, MacOSFactory) would implement these methods, creating the appropriate widgets for their respective operating systems. The client code would use the abstract factory to get the widgets, without knowing the specific OS being targeted.
Advantages:

  • Loose Coupling: Decouples client code from concrete product classes.
  • Flexibility: Easy to add new product families and concrete factories without modifying existing code.
  • Code Reusability: Reduces code duplication by centralizing the object creation logic.

Disadvantages:

  • Adding new products: Requires modifying the abstract factory and all concrete factories. (This can be mitigated with techniques like extending the factory interface, though.)
  • Increased Complexity: Introducing an abstraction layer adds some initial complexity.

In summary, the Abstract Factory pattern is beneficial when you need to create families of related objects without being tied to the concrete implementations, promoting flexibility and maintainability in your software design.
 

The Abstract Design Pattern in C++ is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. It's often implemented using abstract classes and factory methods or abstract factories.

Here’s a simple example illustrating the Abstract Factory Pattern in C++:


Example: GUI Factory

Imagine a cross-platform GUI framework where we need to create buttons and checkboxes for different operating systems (e.g., Windows, macOS).


Abstract Product Interfaces

#include <iostream>
#include <memory>

// Abstract Product: Button
class Button {
public:
    virtual void render() const = 0;
    virtual ~Button() = default;
};

// Abstract Product: Checkbox
class Checkbox {
public:
    virtual void render() const = 0;
    virtual ~Checkbox() = default;
};

Concrete Products

// Concrete Product: WindowsButton
class WindowsButton : public Button {
public:
    void render() const override {
        std::cout << "Rendering a Windows Button.\n";
    }
};

// Concrete Product: MacButton
class MacButton : public Button {
public:
    void render() const override {
        std::cout << "Rendering a Mac Button.\n";
    }
};

// Concrete Product: WindowsCheckbox
class WindowsCheckbox : public Checkbox {
public:
    void render() const override {
        std::cout << "Rendering a Windows Checkbox.\n";
    }
};

// Concrete Product: MacCheckbox
class MacCheckbox : public Checkbox {
public:
    void render() const override {
        std::cout << "Rendering a Mac Checkbox.\n";
    }
};

Abstract Factory Interface

// Abstract Factory
class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() const = 0;
    virtual std::unique_ptr<Checkbox> createCheckbox() const = 0;
    virtual ~GUIFactory() = default;
};

Concrete Factories

// Concrete Factory: WindowsFactory
class WindowsFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() const override {
        return std::make_unique<WindowsButton>();
    }

    std::unique_ptr<Checkbox> createCheckbox() const override {
        return std::make_unique<WindowsCheckbox>();
    }
};

// Concrete Factory: MacFactory
class MacFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() const override {
        return std::make_unique<MacButton>();
    }

    std::unique_ptr<Checkbox> createCheckbox() const override {
        return std::make_unique<MacCheckbox>();
    }
};

Client Code

void renderUI(const GUIFactory& factory) {
    auto button = factory.createButton();
    auto checkbox = factory.createCheckbox();

    button->render();
    checkbox->render();
}

int main() {
    std::cout << "Rendering Windows UI:\n";
    WindowsFactory windowsFactory;
    renderUI(windowsFactory);

    std::cout << "\nRendering Mac UI:\n";
    MacFactory macFactory;
    renderUI(macFactory);

    return 0;
}

Output

Rendering Windows UI:
Rendering a Windows Button.
Rendering a Windows Checkbox.

Rendering Mac UI:
Rendering a Mac Button.
Rendering a Mac Checkbox.

Explanation

  1. Abstract Factory (GUIFactory):

    • Defines an interface for creating families of related objects (Button and Checkbox).

  2. Concrete Factories (WindowsFactory, MacFactory):

    • Implement the creation of specific product instances.

  3. Abstract Products (Button, Checkbox):

    • Define interfaces for the products.

  4. Concrete Products (WindowsButton, MacButton, WindowsCheckbox, MacCheckbox):

    • Implement specific product behavior.

This structure allows adding new product families or variations without altering the client code.


Advantages in Abstract Factory Pattern

1. Flexibility and Extensibility: The Factory Method pattern allows you to add new classes without modifying existing code to create new types of objects. You simply add a new class.
2. Reduced Code Duplication for Object Creation: Code related to object creation is centralized (in the concrete creators), reducing redundancy.
3. Separation of Client Code and Object Creation Code: Client code doesn't need to know the specific class type; it uses objects through an interface or abstract class.
4. Open/Closed Principle (OCP) Compliance: The system can be extended without modifying existing code, adhering to the OCP.
 

Disadvantages in Abstract Factory Pattern

1. Increased Number of Classes: A new ConcreteCreator class must be created for each concrete product, potentially increasing the number of classes in the application.
2. Conceptual Complexity: The Factory Method pattern can add complexity to the design. Overusing the pattern for simple object creation scenarios can make the code harder to understand and maintain.
3. Dependency on Interfaces or Abstract Classes: The client code's reliance on interfaces or abstract classes can sometimes hinder the full utilization of specific object features.
 

Tags Abstract Factory Pattern Creational Design Patterns Creational Patterns Facebook X
Comments 0
Similar posts
  1. Software Design Patterns
    1,435
  2. Builder Pattern - offering pre-defined Interfaces to set Individual Parts
    1,432
  3. Factory Method Pattern allows overriding to return different concrete object types
    1,528
  1. The Blueprint of Success: Why System Design and Architecture Matter?
    399
  2. Software Design Patterns Cheat Sheet
    3,322
  3. Various naming for the Software Architecture - I can't find Component-based Architecture, Functional Architecture
    3,332
  4. Builder Pattern - offering pre-defined Interfaces to set Individual Parts
    1,432
  5. Software Design Patterns
    1,435
  6. Observer Pattern
    2,394
  7. Factory Method Pattern allows overriding to return different concrete object types
    1,528
  8. Optimize the performance of a search results page that experiences high traffic
    142
  9. System Design: High-Traffic Time-Deal Promotion System
    172
  10. Designing Resilient Infrastructure to Prevent Order Data Loss During Kafka Failures
    154
  11. Real-Time Inventory & WMS System Design
    243
  12. Enterprise-Scale 100k+ TPS Order Tracking System Architecture
    203
  13. Enterprise-Scale 100k+ TPS Order Processing System Architecture
    175
  14. Architecting Dynamic Scale-Out and Scale-In with Docker Containers
    133
  15. How to Design Redis Caching in Infrastructure Architecture
    156
  16. Architecture Design - Database Partitioning vs. Sharding
    152
Recently updated
  1. Why 100% SEO Guarantees Better User Engagement and How to Achieve It in Your Service
    39
  2. Why SPF and DKIM Are Essential for Linux Email Servers?
    34
  3. How do I create animated background for Google Meet?
    20,611
  4. MaxMind GeoLite2 vs. DB-IP Lite vs. ip-api.com: Choosing the Right Free IP Geolocation Solution
    244
  5. Meet Valkey: Why Redis Changed Its License, Why Valkey is Better, and How to Use It as a Drop-in Replacement
    94
  6. How Rogue Web Scrapers Are Stealing My Content and Destroying My Server
    157
  7. Array of arguments passed to script in PHP
    90
  8. Invalid Auction Storms in Ad Tech
    98
  9. Building MRC-Compliant Instrumentation in Ad Tech: Implementation Steps and Key Challenges
    202
  10. The Two Clocks of Ad Server Architecture
    70
  11. Frequency Cap Architecture Overview
    514
  12. Collecting Proof-of-Play from 100,000 Screens
    146
  13. Vector Search in Relational Databases (RDBs): Trends & Usage Environments
    287
  14. What is RedisVL?
    109
  15. Designing a Skill Registry Architecture: Minimize Token Usage and Maximize AI Performance
    230
  16. TPU & GPU Cluster Management Tools
    243
  17. The Concept of Scaffolding in AI Agents
    233
  18. Beyond Static Pipelines: Architecting LLM Multi-Agent Systems for Autonomous Workflow Orchestration
    582
  19. AI-DLC vs. AI-SDLC: Model-Centric vs. System-Centric AI Development
    258
  20. Fine-Tuning Open-Weight LLMs: Training, Licensing, and Deploying Custom Models with Ollama
    339
  21. Inside the Next-Generation Streaming Architecture: Ultra-Low Latency, SGAI, and AI Codecs
    202
  22. Machine Learning: Training vs. Ranking
    221
  23. The Continuous Learning Machine: Designing a Loop That Actually Turns
    222
  24. The Next-Gen Low-Latency Standards: LL-HLS & MoQ
    195
  25. Designing a Data Curation System Around a Vector Database
    220
  26. Extracting Context from Live Video: The Architecture Got Simpler When We Stopped Building Features
    256
  27. The New Ad Stack Behind Live Sports Streaming: Inside SGAI, EABN, and the Standards Race to Fix Live Monetization
    656
  28. Designing MLOps Architectures to Handle Seasonal Data Drift in EV Fleet Models
    195
  29. From 15 to 40+ FPS: Accelerating PyTorch Object Detection on Automotive ECUs
    216
  30. Understanding Data Lineage
    260