Skip to content

Abstract Factory

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

Frequency of use: High

UML class diagram

alt

Participants

The classes and objects participating in this pattern are:

  • AbstractFactory  (ContinentFactory)
  • declares an interface for operations that create abstract products
  • ConcreteFactory   (AfricaFactory, AmericaFactory)
  • implements the operations to create concrete product objects
  • AbstractProduct   (Herbivore, Carnivore)
  • declares an interface for a type of product object
  • Product  (Wildebeest, Lion, Bison, Wolf)
  • defines a product object to be created by the corresponding concrete factory
  • implements the AbstractProduct interface
  • Client  (AnimalWorld)
  • uses interfaces declared by AbstractFactory and AbstractProduct classes

Structural code in C# .{10}

This structural code demonstrates the Abstract Factory pattern creating parallel hierarchies of objects. Object creation has been abstracted and there is no need for hard-coded class names in the client code.

using System;

namespace DoFactory.GangOfFour.Abstract.Structural {
  /// <summary>
  /// MainApp startup class for Structural
  /// Abstract Factory Design Pattern.
  /// </summary>

  class MainApp

  {
    /// <summary>
    /// Entry point into console application.
    /// </summary>

    public static void Main() {
      // Abstract factory #1

      AbstractFactory factory1 = new ConcreteFactory1();
      Client client1 = new Client(factory1);
      client1.Run();

      // Abstract factory #2

      AbstractFactory factory2 = new ConcreteFactory2();
      Client client2 = new Client(factory2);
      client2.Run();

      // Wait for user input

      Console.ReadKey();
    }
  }

  /// <summary>
  /// The 'AbstractFactory' abstract class
  /// </summary>

  abstract class AbstractFactory

  {
    public abstract AbstractProductA CreateProductA();
    public abstract AbstractProductB CreateProductB();
  }

  /// <summary>
  /// The 'ConcreteFactory1' class
  /// </summary>

  class ConcreteFactory1: AbstractFactory

  {
    public override AbstractProductA CreateProductA() {
      return new ProductA1();
    }
    public override AbstractProductB CreateProductB() {
      return new ProductB1();
    }
  }

  /// <summary>
  /// The 'ConcreteFactory2' class
  /// </summary>

  class ConcreteFactory2: AbstractFactory

  {
    public override AbstractProductA CreateProductA() {
      return new ProductA2();
    }
    public override AbstractProductB CreateProductB() {
      return new ProductB2();
    }
  }

  /// <summary>
  /// The 'AbstractProductA' abstract class
  /// </summary>

  abstract class AbstractProductA

  {}

  /// <summary>
  /// The 'AbstractProductB' abstract class
  /// </summary>

  abstract class AbstractProductB

  {
    public abstract void Interact(AbstractProductA a);
  }

  /// <summary>
  /// The 'ProductA1' class
  /// </summary>

  class ProductA1: AbstractProductA

  {}

  /// <summary>
  /// The 'ProductB1' class
  /// </summary>

  class ProductB1: AbstractProductB

  {
    public override void Interact(AbstractProductA a) {
      Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name);
    }
  }

  /// <summary>
  /// The 'ProductA2' class
  /// </summary>

  class ProductA2: AbstractProductA

  {}

  /// <summary>
  /// The 'ProductB2' class
  /// </summary>

  class ProductB2: AbstractProductB

  {
    public override void Interact(AbstractProductA a) {
      Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name);
    }
  }

  /// <summary>
  /// The 'Client' class. Interaction environment for the products.
  /// </summary>

  class Client

  {
    private AbstractProductA _abstractProductA;
    private AbstractProductB _abstractProductB;

    // Constructor

    public Client(AbstractFactory factory) {
      _abstractProductB = factory.CreateProductB();
      _abstractProductA = factory.CreateProductA();
    }

    public void Run() {
      _abstractProductB.Interact(_abstractProductA);
    }
  }
}
Output
ProductB1 interacts with ProductA1\
ProductB2 interacts with ProductA2

Real-world code in C# .{20}

This real-world code demonstrates the creation of different animal worlds for a computer game using different factories. Although the animals created by the Continent factories are different, the interactions among the animals remain the same.

using System;

namespace DoFactory.GangOfFour.Abstract.RealWorld {
  /// <summary>
  /// MainApp startup class for Real-World
  /// Abstract Factory Design Pattern.
  /// </summary>

  class MainApp

  {
    /// <summary>
    /// Entry point into console application.
    /// </summary>

    public static void Main() {
      // Create and run the African animal world

      ContinentFactory africa = new AfricaFactory();
      AnimalWorld world = new AnimalWorld(africa);
      world.RunFoodChain();

      // Create and run the American animal world

      ContinentFactory america = new AmericaFactory();
      world = new AnimalWorld(america);
      world.RunFoodChain();

      // Wait for user input

      Console.ReadKey();
    }
  }

  /// <summary>
  /// The 'AbstractFactory' abstract class
  /// </summary>

  abstract class ContinentFactory

  {
    public abstract Herbivore CreateHerbivore();
    public abstract Carnivore CreateCarnivore();
  }

  /// <summary>
  /// The 'ConcreteFactory1' class
  /// </summary>

  class AfricaFactory: ContinentFactory

  {
    public override Herbivore CreateHerbivore() {
      return new Wildebeest();
    }
    public override Carnivore CreateCarnivore() {
      return new Lion();
    }
  }

  /// <summary>
  /// The 'ConcreteFactory2' class
  /// </summary>

  class AmericaFactory: ContinentFactory

  {
    public override Herbivore CreateHerbivore() {
      return new Bison();
    }
    public override Carnivore CreateCarnivore() {
      return new Wolf();
    }
  }

  /// <summary>
  /// The 'AbstractProductA' abstract class
  /// </summary>

  abstract class Herbivore

  {}

  /// <summary>
  /// The 'AbstractProductB' abstract class
  /// </summary>

  abstract class Carnivore

  {
    public abstract void Eat(Herbivore h);
  }

  /// <summary>
  /// The 'ProductA1' class
  /// </summary>

  class Wildebeest: Herbivore

  {}

  /// <summary>
  /// The 'ProductB1' class
  /// </summary>

  class Lion: Carnivore

  {
    public override void Eat(Herbivore h) {
      // Eat Wildebeest

      Console.WriteLine(this.GetType().Name + " eats " + h.GetType().Name);
    }
  }

  /// <summary>
  /// The 'ProductA2' class
  /// </summary>

  class Bison: Herbivore

  {}

  /// <summary>
  /// The 'ProductB2' class
  /// </summary>

  class Wolf: Carnivore

  {
    public override void Eat(Herbivore h) {
      // Eat Bison

      Console.WriteLine(this.GetType().Name + " eats " + h.GetType().Name);
    }
  }

  /// <summary>
  /// The 'Client' class
  /// </summary>

  class AnimalWorld

  {
    private Herbivore _herbivore;
    private Carnivore _carnivore;

    // Constructor

    public AnimalWorld(ContinentFactory factory) {
      _carnivore = factory.CreateCarnivore();
      _herbivore = factory.CreateHerbivore();
    }

    public void RunFoodChain() {
      _carnivore.Eat(_herbivore);
    }
  }
}
Output
Lion eats Wildebeest\
Wolf eats Bison

.NET Optimized code in C#

The .NET optimized code demonstrates the same real-world situation as above but uses modern, built-in .NET features, such as, generics, reflection, LINQ, lambda functions, and more.

alt

```cs{137,141,149} using System; using System.Collections.Generic;

namespace DoFactory.GangOfFour.Abstract.NETOptimized { ///

/// MainApp startup class for .NET optimized /// Abstract Factory Design Pattern. /// class MainApp { /// /// Entry point into console application. /// public static void Main() { // Create and run the African animal world var africa = new AnimalWorld(); africa.RunFoodChain();

        // Create and run the American animal world
        var america = new AnimalWorld<America>();
        america.RunFoodChain();

        // Wait for user input
        Console.ReadKey();
    }
}

/// <summary>
/// The 'AbstractFactory' interface.
/// </summary>
interface IContinentFactory
{
    IHerbivore CreateHerbivore();
    ICarnivore CreateCarnivore();
}

/// <summary>
/// The 'ConcreteFactory1' class.
/// </summary>
class Africa : IContinentFactory
{
    public IHerbivore CreateHerbivore()
    {
        return new Wildebeest();
    }

    public ICarnivore CreateCarnivore()
    {
        return new Lion();
    }
}

/// <summary>
/// The 'ConcreteFactory2' class.
/// </summary>
class America : IContinentFactory
{
    public IHerbivore CreateHerbivore()
    {
        return new Bison();
    }

    public ICarnivore CreateCarnivore()
    {
        return new Wolf();
    }
}

/// <summary>
/// The 'AbstractProductA' interface
/// </summary>
interface IHerbivore
{
}

/// <summary>
/// The 'AbstractProductB' interface
/// </summary>
interface ICarnivore
{
    void Eat(IHerbivore h);
}

/// <summary>
/// The 'ProductA1' class
/// </summary>
class Wildebeest : IHerbivore
{
}

/// <summary>
/// The 'ProductB1' class
/// </summary>
class Lion : ICarnivore
{
    public void Eat(IHerbivore h)
    {
        // Eat Wildebeest
        Console.WriteLine(this.GetType().Name +
            " eats " + h.GetType().Name);
    }
}

/// <summary>
/// The 'ProductA2' class
/// </summary>
class Bison : IHerbivore
{
}

/// <summary>
/// The 'ProductB2' class
/// </summary>
class Wolf : ICarnivore
{
    public void Eat(IHerbivore h)
    {
        // Eat Bison
        Console.WriteLine(this.GetType().Name +
            " eats " + h.GetType().Name);
    }
}

/// <summary>
/// The 'Client' interface
/// </summary>
interface IAnimalWorld
{
    void RunFoodChain();
}

/// <summary>
/// The 'Client' class
/// </summary>
class AnimalWorld<T> : IAnimalWorld where T : IContinentFactory, new()
{
    private IHerbivore _herbivore;
    private ICarnivore _carnivore;
    private T _factory;

    /// <summary>
    /// Contructor of Animalworld
    /// </summary>
    public AnimalWorld()
    {
        // Create new continent factory
        _factory = new T();

        // Factory creates carnivores and herbivores
        _carnivore = _factory.CreateCarnivore();
        _herbivore = _factory.CreateHerbivore();
    }

    /// <summary>
    /// Runs the foodchain, that is, carnivores are eating herbivores.
    /// </summary>
    public void RunFoodChain()
    {
        _carnivore.Eat(_herbivore);
    }
}

} ```