Abstract Factory Design Pattern


Here, we will see how to create Abstract Factory Design Pattern with example.

Abstract Factory Pattern Introduction

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 involves multiple factories, each responsible for creating a set of related objects.

Advantages of the Abstract Factory Pattern

  1. Encapsulation of Object Creation - It separates the creation of objects from their usage, which can be useful for managing complex object creation.
  2. Consistency Among Products - Ensures that products created by a factory are compatible with each other since the factory is designed to produce related objects.
  3. Easy to Extend - Adding new types of products is easier as it only requires the addition of new concrete factories without altering existing code.
  4. Decoupling of Code - Clients interact with the factory and abstract products, which makes the system more modular and easier to maintain.

When to Use the Abstract Factory Pattern

  • When the system needs to be independent of how its products are created, composed, and represented.
  • When the system needs to be configured with multiple families of products.
  • When you want to enforce consistency among a set of products that are designed to work together.
  • When you need to provide a common interface for a set of related or dependent objects, which can be interchangeable.

Problems - A System Without Abstract Factory

Scenario - A cross-platform UI framework without Abstract Factory.

Problems

  • Inconsistent UI: Without an Abstract Factory, creating UI elements for different platforms would be scattered across the codebase. This could lead to inconsistencies in the UI look and feel across different platforms.
  • Difficult to Maintain: Adding support for a new platform would require changes in many parts of the codebase, increasing the risk of bugs and making the system harder to maintain.
  • Code Duplication: Each platform's UI components would likely be created in different places, leading to duplicated code and a lack of a centralized point for platform-specific UI creation.
  • Tight Coupling - Directly instantiating concrete products within code can lead to tight coupling, making it difficult to change the product implementations without modifying the client code.
  • Hard to Extend - Adding new types of products or families requires modifications to existing code, which can be error-prone and difficult to manage.

Example of a System with Abstract Factory

Consider a user interface toolkit that can generate different types of UI elements (buttons, scroll bars, etc.) for different operating systems (Windows, macOS, Linux). Instead of creating UI components directly, you use a factory to create a set of components that are consistent with the specific OS.

  • Abstract Factory - UIFactory
  • Concrete Factories - WindowsFactory, MacOSFactory, LinuxFactory
  • Abstract Products - Button, ScrollBar
  • Concrete Products - WindowsButton, MacOSButton, LinuxButton, WindowsScrollBar, MacOSScrollBar, LinuxScrollBar

Example

using System;

// Abstract Products
public interface IButton
{
    void Paint();
}

public interface IScrollBar
{
    void Render();
}

// Concrete Products for Windows
public class WindowsButton : IButton
{
    public void Paint()
    {
        Console.WriteLine("Rendering Windows Button");
    }
}

public class WindowsScrollBar : IScrollBar
{
    public void Render()
    {
        Console.WriteLine("Rendering Windows Scroll Bar");
    }
}

// Concrete Products for macOS
public class MacOSButton : IButton
{
    public void Paint()
    {
        Console.WriteLine("Rendering macOS Button");
    }
}

public class MacOSScrollBar : IScrollBar
{
    public void Render()
    {
        Console.WriteLine("Rendering macOS Scroll Bar");
    }
}

// Concrete Products for Linux
public class LinuxButton : IButton
{
    public void Paint()
    {
        Console.WriteLine("Rendering Linux Button");
    }
}

public class LinuxScrollBar : IScrollBar
{
    public void Render()
    {
        Console.WriteLine("Rendering Linux Scroll Bar");
    }
}

// Abstract Factory
public interface IUIFactory
{
    IButton CreateButton();
    IScrollBar CreateScrollBar();
}

// Concrete Factories
public class WindowsFactory : IUIFactory
{
    public IButton CreateButton()
    {
        return new WindowsButton();
    }

    public IScrollBar CreateScrollBar()
    {
        return new WindowsScrollBar();
    }
}

public class MacOSFactory : IUIFactory
{
    public IButton CreateButton()
    {
        return new MacOSButton();
    }

    public IScrollBar CreateScrollBar()
    {
        return new MacOSScrollBar();
    }
}

public class LinuxFactory : IUIFactory
{
    public IButton CreateButton()
    {
        return new LinuxButton();
    }

    public IScrollBar CreateScrollBar()
    {
        return new LinuxScrollBar();
    }
}

// Client
public class Client
{
    private readonly IButton _button;
    private readonly IScrollBar _scrollBar;

    public Client(IUIFactory factory)
    {
        _button = factory.CreateButton();
        _scrollBar = factory.CreateScrollBar();
    }

    public void Run()
    {
        _button.Paint();
        _scrollBar.Render();
    }
}

// Main Program
class Program
{
    static void Main(string[] args)
    {
        IUIFactory factory = new WindowsFactory(); // Choose the factory based on the OS
        Client client = new Client(factory);
        client.Run();

        factory = new MacOSFactory(); // Switch to macOS factory
        client = new Client(factory);
        client.Run();

        factory = new LinuxFactory(); // Switch to Linux factory
        client = new Client(factory);
        client.Run();
    }
}

Explanation

  • Abstract Products (IButton, IScrollBar) define the common interface for UI components.
  • Concrete Products (WindowsButton, MacOSButton, LinuxButton, etc.) provide specific implementations for each OS.
  • Abstract Factory (IUIFactory) declares methods for creating abstract products.
  • Concrete Factories (WindowsFactory, MacOSFactory, LinuxFactory) implement methods to create concrete products.
  • Client uses the factory to create products and interact with them without knowing their concrete types.

Output

Abstract Factory Design Pattern

Real-World Example - Abstract Factory Pattern Car Manufacturing Company

Think of a car manufacturing company that produces different models of cars (sedans, SUVs) and different trims (luxury, standard). Each model and trim has its own set of components like seats, wheels, and engines.

  • Abstract Factory - CarFactory
  • Concrete Factories - SedanFactory, SUVFactory
  • Abstract Products - Seats, Wheels, Engine
  • Concrete Products - SedanSeats, SUVSeats, SedanWheels, SUVWheels, SedanEngine, SUVEngine

When you choose a SedanFactory, you get a set of components that are specifically designed for a sedan. Similarly, SUVFactory provides components designed for SUVs.

Example

// Abstract Products
using System;

public interface ISeats
{
    string GetSeatType();
}

public interface IWheels
{
    string GetWheelType();
}

public interface IEngine
{
    string GetEngineType();
}

// Concrete Products for Sedan
public class SedanSeats : ISeats
{
    public string GetSeatType() => "Luxury Leather Seats for Sedan";
}

public class SedanWheels : IWheels
{
    public string GetWheelType() => "Alloy Wheels for Sedan";
}

public class SedanEngine : IEngine
{
    public string GetEngineType() => "V6 Engine for Sedan";
}

// Concrete Products for SUV
public class SUVSeats : ISeats
{
    public string GetSeatType() => "Luxury Leather Seats for SUV";
}

public class SUVWheels : IWheels
{
    public string GetWheelType() => "Off-road Wheels for SUV";
}

public class SUVEngine : IEngine
{
    public string GetEngineType() => "V8 Engine for SUV";
}

// Abstract Factory
public interface ICarFactory
{
    ISeats CreateSeats();
    IWheels CreateWheels();
    IEngine CreateEngine();
}

// Concrete Factories
public class SedanFactory : ICarFactory
{
    public ISeats CreateSeats() => new SedanSeats();
    public IWheels CreateWheels() => new SedanWheels();
    public IEngine CreateEngine() => new SedanEngine();
}

public class SUVFactory : ICarFactory
{
    public ISeats CreateSeats() => new SUVSeats();
    public IWheels CreateWheels() => new SUVWheels();
    public IEngine CreateEngine() => new SUVEngine();
}

// Client Code
public class CarManufacturer
{
    private readonly ISeats _seats;
    private readonly IWheels _wheels;
    private readonly IEngine _engine;

    public CarManufacturer(ICarFactory factory)
    {
        _seats = factory.CreateSeats();
        _wheels = factory.CreateWheels();
        _engine = factory.CreateEngine();
    }

    public void DisplayCarDetails()
    {
        Console.WriteLine($"Seats: {_seats.GetSeatType()}");
        Console.WriteLine($"Wheels: {_wheels.GetWheelType()}");
        Console.WriteLine($"Engine: {_engine.GetEngineType()}");
    }
}

// Usage
class Program
{
    static void Main(string[] args)
    {
        // Create a sedan
        ICarFactory sedanFactory = new SedanFactory();
        CarManufacturer sedan = new CarManufacturer(sedanFactory);
        sedan.DisplayCarDetails();

        Console.WriteLine();

        // Create an SUV
        ICarFactory suvFactory = new SUVFactory();
        CarManufacturer suv = new CarManufacturer(suvFactory);
        suv.DisplayCarDetails();
    }
}

Output

Abstract Factory Design Pattern

Application of Abstract Factory Design Pattern

  • UI Frameworks - To create a consistent look and feel across different platforms.
  • Game Development - To generate game characters, environments, and objects that are consistent with the chosen game theme or style.
  • Database Access - To create connections, commands, and queries that are consistent with different database systems (SQL Server, Oracle, MySQL).

Prev Next

Top Articles

  1. What is JSON
  2. How to convert a javaScript object in JSON object
  3. Some Important JSON Examples
  4. Common JSON Interview Question