Abstract Factory¶
- Abstract Factory
- UML class diagram
- Participants
- Structural code in C# .{10} - Output
- Real-world code in C# .{20} - Output
- .NET Optimized code in C# {30}
Summary: 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# .{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¶
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¶
.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.
```cs{137,141,149} using System; using System.Collections.Generic;
namespace DoFactory.GangOfFour.Abstract.NETOptimized { ///
// 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);
}
}
} ```