.NET Design Patterns

Abstract Factory


 Definition
 UML diagram
 Participants
 Structural code in C#
 Real-world code in C#
 .NET Optimized code in C#



Definition

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

Frequency of use:
High




UML class diagram






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#


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#


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, object initializers, automatic properties, etc. You can find an example on our Singleton pattern page.

All other patterns (and much more) are available in our .NET Design Pattern Framework 4.5.


Not only does the .NET Design Pattern Framework 4.5 cover GOF and Enterprise patterns, it also includes .NET pattern architectures that reduce the code you need to write by up to 75%. This unique package will change your .NET lifestyle -- for only $79.  Here's what is included:



  • 69 gang-of-four pattern projects
  • 46 head-first pattern projects
  • Fowler's enterprise patterns
  • Multi-tier patterns
  • Convention over configuration
  • Active Record and CQRS patterns
  • Repository and Unit-of-Work patterns
  • MVC, MVP, & MVVM patterns
  • REST patterns with Web API
  • SparkTM Rapid App Dev (RAD) platform!
  • Art Shop MVC Reference Application
  • 100% pure source code