02 Dec 2023



Advanced

Real-world examples of the Abstract Factory Pattern:

  1. GUI Libraries: GUI frameworks often use the Abstract Factory Pattern to provide different look-and-feel implementations for various operating systems. For instance, the creation of buttons, windows, and other UI components might be abstracted through an abstract factory, and different implementations for Windows, macOS, and Linux can be provided.
// Abstract Factory Interface
interface GUIFactory
{
    Button CreateButton();
    Window CreateWindow();
}

// Concrete Factories
class WindowsFactory : GUIFactory
{
    public Button CreateButton() => new WindowsButton();
    public Window CreateWindow() => new WindowsWindow();
}

class MacOSFactory : GUIFactory
{
    public Button CreateButton() => new MacOSButton();
    public Window CreateWindow() => new MacOSWindow();
}

// Abstract Product Interfaces
interface Button
{
    void Render();
}

interface Window
{
    void Render();
}

// Concrete Products
class WindowsButton : Button
{
    public void Render() => Console.WriteLine("Rendering Windows Button");
}

class WindowsWindow : Window
{
    public void Render() => Console.WriteLine("Rendering Windows Window");
}

class MacOSButton : Button
{
    public void Render() => Console.WriteLine("Rendering MacOS Button");
}

class MacOSWindow : Window
{
    public void Render() => Console.WriteLine("Rendering MacOS Window");
}

// Client Code
class Client
{
    private GUIFactory factory;

    public Client(GUIFactory factory)
    {
        this.factory = factory;
    }

    public void CreateUI()
    {
        Button button = factory.CreateButton();
        Window window = factory.CreateWindow();

        button.Render();
        window.Render();
    }
}
class Program
{
    static void Main()
    {
        // Usage
        var windowsClient = new Client(new WindowsFactory());
        windowsClient.CreateUI();
        
        var macOsClient = new Client(new MacOSFactory());
        macOsClient.CreateUI();
    }
}
  1. Database Drivers: Consider a database access library that needs to support multiple database systems like MySQL, PostgreSQL, and SQLite. The Abstract Factory Pattern can be employed to define a common interface for creating database connection objects, query builders, and other components. Concrete factories would then implement this interface for each specific database.
// Abstract Factory Interface
interface DatabaseFactory
{
    Connection CreateConnection();
    QueryBuilder CreateQueryBuilder();
}

// Concrete Factories
class MySqlConnectionFactory : DatabaseFactory
{
    public Connection CreateConnection() => new MySqlConnection();
    public QueryBuilder CreateQueryBuilder() => new MySqlQueryBuilder();
}

class PostgreSqlConnectionFactory : DatabaseFactory
{
    public Connection CreateConnection() => new PostgreSqlConnection();
    public QueryBuilder CreateQueryBuilder() => new PostgreSqlQueryBuilder();
}

// Abstract Product Interfaces
interface Connection
{
    void Connect();
}

interface QueryBuilder
{
    string BuildQuery();
}

// Concrete Products
class MySqlConnection : Connection
{
    public void Connect() => Console.WriteLine("Connecting to MySQL database");
}

class MySqlQueryBuilder : QueryBuilder
{
    public string BuildQuery() => "Building MySQL query";
}

class PostgreSqlConnection : Connection
{
    public void Connect() => Console.WriteLine("Connecting to PostgreSQL database");
}

class PostgreSqlQueryBuilder : QueryBuilder
{
    public string BuildQuery() => "Building PostgreSQL query";
}

// Client Code
class DatabaseClient
{
    private DatabaseFactory factory;

    public DatabaseClient(DatabaseFactory factory)
    {
        this.factory = factory;
    }

    public void ExecuteQuery()
    {
        Connection connection = factory.CreateConnection();
        QueryBuilder queryBuilder = factory.CreateQueryBuilder();

        connection.Connect();
        Console.WriteLine(queryBuilder.BuildQuery());
    }
}

class Program
{
    static void Main()
    {
        // Usage
        var mySqlClient = new DatabaseClient(new MySqlConnectionFactory());
        mySqlClient.ExecuteQuery();
        
        var postgreSqlClient = new DatabaseClient(new PostgreSqlConnectionFactory());
        postgreSqlClient.ExecuteQuery();
    }
}
  1. Vehicle Manufacturing: In the automotive industry, an abstract factory could represent a set of interfaces for creating different components of a vehicle, such as engines, tires, and interiors. Concrete factories would implement these interfaces for specific types of vehicles like sedans, SUVs, or trucks.
// Abstract Factory Interface
interface VehicleFactory
{
    Engine CreateEngine();
    Tire CreateTire();
    Interior CreateInterior();
}

// Concrete Factories
class SedanFactory : VehicleFactory
{
    public Engine CreateEngine() => new SedanEngine();
    public Tire CreateTire() => new SedanTire();
    public Interior CreateInterior() => new SedanInterior();
}

class SUVFactory : VehicleFactory
{
    public Engine CreateEngine() => new SUVEngine();
    public Tire CreateTire() => new SUVTire();
    public Interior CreateInterior() => new SUVInterior();
}

// Abstract Product Interfaces
interface Engine
{
    void Start();
}

interface Tire
{
    void Inflate();
}

interface Interior
{
    void Decorate();
}

// Concrete Products
class SedanEngine : Engine
{
    public void Start() => Console.WriteLine("Starting Sedan Engine");
}

class SedanTire : Tire
{
    public void Inflate() => Console.WriteLine("Inflating Sedan Tire");
}

class SedanInterior : Interior
{
    public void Decorate() => Console.WriteLine("Decorating Sedan Interior");
}

class SUVEngine : Engine
{
    public void Start() => Console.WriteLine("Starting SUV Engine");
}

class SUVTire : Tire
{
    public void Inflate() => Console.WriteLine("Inflating SUV Tire");
}

class SUVInterior : Interior
{
    public void Decorate() => Console.WriteLine("Decorating SUV Interior");
}

// Client Code
class VehicleClient
{
    private VehicleFactory factory;

    public VehicleClient(VehicleFactory factory)
    {
        this.factory = factory;
    }

    public void AssembleVehicle()
    {
        Engine engine = factory.CreateEngine();
        Tire tire = factory.CreateTire();
        Interior interior = factory.CreateInterior();

        engine.Start();
        tire.Inflate();
        interior.Decorate();
    }
}

class Program
{
    static void Main()
    {
    // Usage
    var sedanClient = new VehicleClient(new SedanFactory());
    sedanClient.AssembleVehicle();
    
    var suvClient = new VehicleClient(new SUVFactory());
    suvClient.AssembleVehicle();
    }
}
  1. Theme Management: Consider an application that supports different themes, each with its own set of colors, fonts, and styles. An abstract factory can be employed to create theme-specific objects, ensuring that all UI components within a theme are consistent.
// Abstract Factory Interface
interface ThemeFactory
{
    ColorPalette CreateColorPalette();
    FontSet CreateFontSet();
    StyleConfiguration CreateStyleConfiguration();
}

// Concrete Factories
class LightThemeFactory : ThemeFactory
{
    public ColorPalette CreateColorPalette() => new LightColorPalette();
    public FontSet CreateFontSet() => new LightFontSet();
    public StyleConfiguration CreateStyleConfiguration() => new LightStyleConfiguration();
}

class DarkThemeFactory : ThemeFactory
{
    public ColorPalette CreateColorPalette() => new DarkColorPalette();
    public FontSet CreateFontSet() => new DarkFontSet();
    public StyleConfiguration CreateStyleConfiguration() => new DarkStyleConfiguration();
}

// Abstract Product Interfaces
interface ColorPalette
{
    void ApplyColors();
}

interface FontSet
{
    void ApplyFonts();
}

interface StyleConfiguration
{
    void ApplyStyles();
}

// Concrete Products
class LightColorPalette : ColorPalette
{
    public void ApplyColors() => Console.WriteLine("Applying Light Theme Colors");
}

class LightFontSet : FontSet
{
    public void ApplyFonts() => Console.WriteLine("Applying Light Theme Fonts");
}

class LightStyleConfiguration : StyleConfiguration
{
    public void ApplyStyles() => Console.WriteLine("Applying Light Theme Styles");
}

class DarkColorPalette : ColorPalette
{
    public void ApplyColors() => Console.WriteLine("Applying Dark Theme Colors");
}

class DarkFontSet : FontSet
{
    public void ApplyFonts() => Console.WriteLine("Applying Dark Theme Fonts");
}

class DarkStyleConfiguration : StyleConfiguration
{
    public void ApplyStyles() => Console.WriteLine("Applying Dark Theme Styles");
}

// Client Code
class ThemeClient
{
    private ThemeFactory factory;

    public ThemeClient(ThemeFactory factory)
    {
        this.factory = factory;
    }

    public void ApplyTheme()
    {
        ColorPalette colorPalette = factory.CreateColorPalette();
        FontSet fontSet = factory.CreateFontSet();
        StyleConfiguration styleConfiguration = factory.CreateStyleConfiguration();

        colorPalette.ApplyColors();
        fontSet.ApplyFonts();
        styleConfiguration.ApplyStyles();
    }
}

class Program
{
    static void Main()
    {
    // Usage
    var lightThemeClient = new ThemeClient(new LightThemeFactory());
    lightThemeClient.ApplyTheme();
    
    var darkThemeClient = new ThemeClient(new DarkThemeFactory());
    darkThemeClient.ApplyTheme();
    }
}
  1. Document Processing: In a document processing system, an abstract factory can be used to create objects for handling different document types (e.g., PDF, Word, HTML). Concrete factories would then implement the creation of specific document-related objects.
// Abstract Factory Interface
interface DocumentFactory
{
    DocumentReader CreateReader();
    DocumentWriter CreateWriter();
}

// Concrete Factories
class PDFDocumentFactory : DocumentFactory
{
    public DocumentReader CreateReader() => new PDFDocumentReader();
    public DocumentWriter CreateWriter() => new PDFDocumentWriter();
}

class WordDocumentFactory : DocumentFactory
{
    public DocumentReader CreateReader() => new WordDocumentReader();
    public DocumentWriter CreateWriter() => new WordDocumentWriter();
}

// Abstract Product Interfaces
interface DocumentReader
{
    void Read();
}

interface DocumentWriter
{
    void Write();
}

// Concrete Products
class PDFDocumentReader : DocumentReader
{
    public void Read() => Console.WriteLine("Reading PDF Document");
}

class PDFDocumentWriter : DocumentWriter
{
    public void Write() => Console.WriteLine("Writing PDF Document");
}

class WordDocumentReader : DocumentReader
{
    public void Read() => Console.WriteLine("Reading Word Document");
}

class WordDocumentWriter : DocumentWriter
{
    public void Write() => Console.WriteLine("Writing Word Document");
}

// Client Code
class DocumentClient
{
    private DocumentFactory factory;

    public DocumentClient(DocumentFactory factory)
    {
        this.factory = factory;
    }

    public void ProcessDocument()
    {
        DocumentReader reader = factory.CreateReader();
        DocumentWriter writer = factory.CreateWriter();

        reader.Read();
        writer.Write();
    }
}

class Program
{
    static void Main()
    {
        // Usage
        var pdfDocumentClient = new DocumentClient(new PDFDocumentFactory());
        pdfDocumentClient.ProcessDocument();
        
        var wordDocumentClient = new DocumentClient(new WordDocumentFactory());
        wordDocumentClient.ProcessDocument();
    }
}
  1. Logging Libraries: Abstract Factory Pattern can be applied in logging libraries where different loggers (file logger, console logger, database logger) can be created through a common interface. This allows the application to switch between logging implementations without modifying the code extensively.
// Abstract Factory Interface
interface LoggerFactory
{
    Logger CreateLogger();
    LogFormatter CreateLogFormatter();
}

// Concrete Factories
class FileLoggerFactory : LoggerFactory
{
    public Logger CreateLogger() => new FileLogger();
    public LogFormatter CreateLogFormatter() => new FileLogFormatter();
}

class ConsoleLoggerFactory : LoggerFactory
{
    public Logger CreateLogger() => new ConsoleLogger();
    public LogFormatter CreateLogFormatter() => new ConsoleLogFormatter();
}

// Abstract Product Interfaces
interface Logger
{
    void Log(string message);
}

interface LogFormatter
{
    string FormatLog(string message);
}

// Concrete Products
class FileLogger : Logger
{
    public void Log(string message) => Console.WriteLine($"Logging to file: {message}");
}

class FileLogFormatter : LogFormatter
{
    public string FormatLog(string message) => $"[File Log] {message}";
}

class ConsoleLogger : Logger
{
    public void Log(string message) => Console.WriteLine($"Logging to console: {message}");
}

class ConsoleLogFormatter : LogFormatter
{
    public string FormatLog(string message) => $"[Console Log] {message}";
}

// Client Code
class LoggingClient
{
    private LoggerFactory factory;

    public LoggingClient(LoggerFactory factory)
    {
        this.factory = factory;
    }

    public void LogMessage(string message)
    {
        Logger logger = factory.CreateLogger();
        LogFormatter formatter = factory.CreateLogFormatter();

        string formattedMessage = formatter.FormatLog(message);
        logger.Log(formattedMessage);
    }
}

class Program
{
    static void Main()
    {
    // Usage
    var fileLoggerClient = new LoggingClient(new FileLoggerFactory());
    fileLoggerClient.LogMessage("This is a log message");
    
    var consoleLoggerClient = new LoggingClient(new ConsoleLoggerFactory());
    consoleLoggerClient.LogMessage("This is another log message");
    }
}
software-design-patterns
abstract-factory-design-pattern
real-world-examples
examples