Abstract Factory Design Pattern: Comprehensive Explanation

The Abstract Factory pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. It belongs to the Gang of Four (GoF) patterns and promotes loose coupling, consistency, and extensibility in object-oriented systems.


Core Intent

“Provide an interface for creating families of related or dependent objects without specifying their concrete classes.”

This enables the client to work with high-level abstractions while allowing the system to instantiate consistent product groups at runtime.


When to Use Abstract Factory

ScenarioUse Case
Multiple product families exist (e.g., UI themes, regional configurations)Ensure all components belong to the same family
Client must be independent of how products are createdPromote decoupling
System must support swapping entire product familiesRuntime configuration
Product creation logic is complex and varies per familyEncapsulate creation rules

Avoid when:

  • Only one product type is needed → Use Factory Method
  • Products are unrelated → Simple instantiation suffices

Where It Is Used in Real Systems

DomainExample
GUI ToolkitsWindows vs macOS widgets (buttons, dialogs)
Game DevelopmentWeapon systems per era (Medieval, Modern)
E-CommerceRegional payment, tax, shipping, currency
Database DriversOracle vs SQL Server connection factories
IoT PlatformsDevice-specific sensor/actuator families

Key Benefits

  • Consistency: Guarantees compatible objects within a family.
  • Extensibility: Add new families without modifying client.
  • Open/Closed Principle: Open for extension, closed for modification.
  • Testability: Easy to inject mock factories.

Real-World Example: E-Commerce Regional Checkout System

An e-commerce platform operates globally. The checkout process varies by region due to:

  • Different payment gateways
  • Unique tax rules
  • Local shipping providers
  • Region-specific currency formatting

We define three product families: US, EU, and India.

Each family includes:

  • IPaymentProcessor
  • ITaxCalculator
  • IShippingProvider
  • ICurrencyFormatter

The client (CheckoutService) remains unaware of concrete implementations.

C# Implementation

using System;

// ==================== ABSTRACT PRODUCTS ====================

public interface IPaymentProcessor
{
    bool ProcessPayment(decimal amount, string currencyCode);
}

public interface ITaxCalculator
{
    decimal CalculateTax(decimal subtotal, string regionCode);
}

public interface IShippingProvider
{
    decimal CalculateShipping(decimal weightKg, string destination);
    string GetTrackingUrl(string orderId);
}

public interface ICurrencyFormatter
{
    string Format(decimal amount);
    string CurrencyCode { get; }
}

// ==================== CONCRETE PRODUCTS: US ====================

public class StripeProcessor : IPaymentProcessor
{
    public bool ProcessPayment(decimal amount, string currencyCode)
    {
        Console.WriteLine($"[US] Processing {currencyCode}{amount:F2} via Stripe...");
        return true; // Simulate success
    }
}

public class SalesTaxCalculator : ITaxCalculator
{
    public decimal CalculateTax(decimal subtotal, string regionCode)
    {
        decimal rate = regionCode == "CA" ? 0.0875m : 0.06m; // Example rates
        return subtotal * rate;
    }
}

public class FedExProvider : IShippingProvider
{
    public decimal CalculateShipping(decimal weightKg, string destination)
        => weightKg * 5.50m;

    public string GetTrackingUrl(string orderId)
        => $"https://fedex.com/track/{orderId}";
}

public class USDCurrencyFormatter : ICurrencyFormatter
{
    public string Format(decimal amount) => $"${amount:F2}";
    public string CurrencyCode => "USD";
}

// ==================== CONCRETE PRODUCTS: EU ====================

public class AdyenProcessor : IPaymentProcessor
{
    public bool ProcessPayment(decimal amount, string currencyCode)
    {
        Console.WriteLine($"[EU] Processing {currencyCode}{amount:F2} via Adyen...");
        return true;
    }
}

public class VATCalculator : ITaxCalculator
{
    public decimal CalculateTax(decimal subtotal, string regionCode)
        => subtotal * 0.20m; // Standard 20% VAT
}

public class DHLProvider : IShippingProvider
{
    public decimal CalculateShipping(decimal weightKg, string destination)
        => weightKg * 8.90m;

    public string GetTrackingUrl(string orderId)
        => $"https://dhl.com/track/{orderId}";
}

public class EURCurrencyFormatter : ICurrencyFormatter
{
    public string Format(decimal amount) => $"€{amount:F2}";
    public string CurrencyCode => "EUR";
}

// ==================== CONCRETE PRODUCTS: INDIA ====================

public class RazorpayProcessor : IPaymentProcessor
{
    public bool ProcessPayment(decimal amount, string currencyCode)
    {
        Console.WriteLine($"[IN] Processing {currencyCode}{amount:F2} via Razorpay...");
        return true;
    }
}

public class GSTCalculator : ITaxCalculator
{
    public decimal CalculateTax(decimal subtotal, string regionCode)
        => subtotal * 0.18m; // 18% GST
}

public class DelhiveryProvider : IShippingProvider
{
    public decimal CalculateShipping(decimal weightKg, string destination)
        => weightKg * 65.00m;

    public string GetTrackingUrl(string orderId)
        => $"https://delhivery.com/track/{orderId}";
}

public class INRCurrencyFormatter : ICurrencyFormatter
{
    public string Format(decimal amount) => $"₹{amount:F2}";
    public string CurrencyCode => "INR";
}

// ==================== ABSTRACT FACTORY ====================

public interface ICheckoutFactory
{
    IPaymentProcessor CreatePaymentProcessor();
    ITaxCalculator CreateTaxCalculator();
    IShippingProvider CreateShippingProvider();
    ICurrencyFormatter CreateCurrencyFormatter();
}

// ==================== CONCRETE FACTORIES ====================

public class USCheckoutFactory : ICheckoutFactory
{
    public IPaymentProcessor CreatePaymentProcessor() => new StripeProcessor();
    public ITaxCalculator CreateTaxCalculator() => new SalesTaxCalculator();
    public IShippingProvider CreateShippingProvider() => new FedExProvider();
    public ICurrencyFormatter CreateCurrencyFormatter() => new USDCurrencyFormatter();
}

public class EUCheckoutFactory : ICheckoutFactory
{
    public IPaymentProcessor CreatePaymentProcessor() => new AdyenProcessor();
    public ITaxCalculator CreateTaxCalculator() => new VATCalculator();
    public IShippingProvider CreateShippingProvider() => new DHLProvider();
    public ICurrencyFormatter CreateCurrencyFormatter() => new EURCurrencyFormatter();
}

public class INCheckoutFactory : ICheckoutFactory
{
    public IPaymentProcessor CreatePaymentProcessor() => new RazorpayProcessor();
    public ITaxCalculator CreateTaxCalculator() => new GSTCalculator();
    public IShippingProvider CreateShippingProvider() => new DelhiveryProvider();
    public ICurrencyFormatter CreateCurrencyFormatter() => new INRCurrencyFormatter();
}

// ==================== CLIENT ====================

public class CheckoutService
{
    private readonly IPaymentProcessor _paymentProcessor;
    private readonly ITaxCalculator _taxCalculator;
    private readonly IShippingProvider _shippingProvider;
    private readonly ICurrencyFormatter _currencyFormatter;

    public CheckoutService(ICheckoutFactory factory)
    {
        _paymentProcessor = factory.CreatePaymentProcessor();
        _taxCalculator = factory.CreateTaxCalculator();
        _shippingProvider = factory.CreateShippingProvider();
        _currencyFormatter = factory.CreateCurrencyFormatter();
    }

    public void ProcessCheckout(decimal subtotal, decimal weightKg, string regionCode, string orderId)
    {
        decimal tax = _taxCalculator.CalculateTax(subtotal, regionCode);
        decimal shipping = _shippingProvider.CalculateShipping(weightKg, regionCode);
        decimal total = subtotal + tax + shipping;

        string formattedSubtotal = _currencyFormatter.Format(subtotal);
        string formattedTax = _currencyFormatter.Format(tax);
        string formattedShipping = _currencyFormatter.Format(shipping);
        string formattedTotal = _currencyFormatter.Format(total);

        Console.WriteLine("=== Checkout Summary ===");
        Console.WriteLine($"Subtotal:   {formattedSubtotal}");
        Console.WriteLine($"Tax:        {formattedTax}");
        Console.WriteLine($"Shipping:   {formattedShipping}");
        Console.WriteLine($"Total:      {formattedTotal}");

        bool paid = _paymentProcessor.ProcessPayment(total, _currencyFormatter.CurrencyCode);
        if (paid)
        {
            Console.WriteLine($"Payment successful. Tracking: {_shippingProvider.GetTrackingUrl(orderId)}");
        }
    }
}

// ==================== FACTORY PROVIDER ====================

public static class CheckoutFactoryProvider
{
    public static ICheckoutFactory GetFactory(string region)
    {
        return region.ToUpper() switch
        {
            "US" => new USCheckoutFactory(),
            "EU" => new EUCheckoutFactory(),
            "IN" => new INCheckoutFactory(),
            _ => throw new NotSupportedException($"Region '{region}' is not supported.")
        };
    }
}

// ==================== DEMO ====================

class Program
{
    static void Main()
    {
        Console.WriteLine("E-COMMERCE CHECKOUT USING ABSTRACT FACTORY\n");

        // US Checkout
        var usCheckout = new CheckoutService(CheckoutFactoryProvider.GetFactory("US"));
        usCheckout.ProcessCheckout(100.00m, 2.5m, "CA", "ORD-1001");

        Console.WriteLine();

        // EU Checkout
        var euCheckout = new CheckoutService(CheckoutFactoryProvider.GetFactory("EU"));
        euCheckout.ProcessCheckout(100.00m, 2.5m, "DE", "ORD-1002");

        Console.WriteLine();

        // India Checkout
        var inCheckout = new CheckoutService(CheckoutFactoryProvider.GetFactory("IN"));
        inCheckout.ProcessCheckout(1000.00m, 1.0m, "MH", "ORD-1003");
    }
}

Sample Output

E-COMMERCE CHECKOUT USING ABSTRACT FACTORY

=== Checkout Summary ===
Subtotal:   $100.00
Tax:        $8.75
Shipping:   $13.75
Total:      $122.50
[US] Processing USD122.50 via Stripe...
Payment successful. Tracking: https://fedex.com/track/ORD-1001

=== Checkout Summary ===
Subtotal:   €100.00
Tax:        €20.00
Shipping:   €22.25
Total:      €142.25
[EU] Processing EUR142.25 via Adyen...
Payment successful. Tracking: https://dhl.com/track/ORD-1002

=== Checkout Summary ===
Subtotal:   ₹1000.00
Tax:        ₹180.00
Shipping:   ₹65.00
Total:      ₹1245.00
[IN] Processing INR1245.00 via Razorpay...
Payment successful. Tracking: https://delhivery.com/track/ORD-1003

UML Class Diagram

Participants in the Abstract Factory Pattern

The classes and objects participating in this pattern include:

  • AbstractFactory (ICheckoutFactory)
    • Declares an interface for operations that create abstract product objects.
  • ConcreteFactory (USCheckoutFactory, EUCheckoutFactory, INCheckoutFactory)
    • Implements the operations to create concrete product objects.
  • AbstractProduct (IPaymentProcessor, ITaxCalculator, IShippingProvider, ICurrencyFormatter)
    • Declares an interface for a type of product object.
  • Product (StripeProcessor, AdyenProcessor, RazorpayProcessor, SalesTaxCalculator, VATCalculator, etc.)
    • Defines a product object to be created by the corresponding concrete factory.
    • Implements the AbstractProduct interface.
  • Client (CheckoutService)
    • Uses only interfaces declared by AbstractFactory and AbstractProduct classes.

Summary

ElementRole in E-Commerce Example
AbstractFactoryICheckoutFactory defines contract for creating regional services
ConcreteFactoryUSCheckoutFactory, EUCheckoutFactory, INCheckoutFactory
AbstractProductInterfaces for payment, tax, shipping, currency
ProductConcrete implementations per region
ClientCheckoutService — works with abstractions only

The Abstract Factory pattern ensures regional consistency, global scalability, and clean separation of concerns — making it a cornerstone of enterprise e-commerce architectures.

Uma Mahesh
Uma Mahesh

Author is working as an Architect in a reputed software company. He is having nearly 21+ Years of experience in web development using Microsoft Technologies.

Articles: 288