BlackWasp
Design Patterns
.NET 1.1+

Abstract Factory Design Pattern

The abstract factory pattern is a design pattern that allows for the creation of groups of related objects without the requirement of specifying the exact concrete classes that will be used. One of a number of factory classes generates the object sets.

What is the Abstract Factory Pattern?

The abstract factory pattern is a Gang of Four design pattern. This is a creational pattern as it is used to control class instantiation. The abstract factory pattern is used to provide a client with a set of related or dependant objects. The "family" of objects created by the factory are determined at run-time according to the selection of concrete factory class made.

As an example, consider a program that assists with the packaging and delivery of items for a web-based store. The company delivers two types of product. The first is a standard product that is placed in a box and delivered through the post with a simple label. The second is a delicate item that requires shockproof packaging and is delivered via a courier that requires a detailed manifest document.

In this situation, there are two types of object required, a packaging object and a delivery documentation object. We could use two factories to generate these related objects. The StandardPurchaseFactory may produce StandardPackaging and PostalLabel objects whilst the DelicatePurchaseFactory creates ShockProofPackaging and CourierManifest objects.

Implementing the Factory Method Pattern

Abstract Factory Design Pattern UML

The UML class diagram above describes an implementation of the abstract factory design pattern. The classes in the diagram are described below:

  • Client. This is the class that uses the factories to generate a family of related objects. In the UML diagram, the client has two private fields that hold instances of the abstract product classes. The underlying objects will be related to each other but the actual types can remain unknown, as they will only be accessed via their base class interfaces. When a client is instantiated, a concrete factory object is passed to the constructor and used to populate the private fields.
  • AbstractFactory. This is an abstract base class for the concrete factory classes that will generate new sets of related objects. A method is included for each type of object that will be instantiated. This class could be replaced with a simple interface. However, generally an abstract class will be used so that other standard functionality can be included and inherited by all of the concrete factory subclasses.
  • ConcreteFactory (A/B). Inheriting from the AbstractFactory class, the concrete factory classes override the methods that generate the suite of objects required by the client. There may be any number of concrete factories depending upon the requirements of the software.
  • AbstractProduct (A/B). This abstract class is the base class for the types of object that a factory can create. One base type exists for each of the distinct types of product required by the client.
  • ConcreteProduct (A/B). Multiple subclasses of the ConcreteProduct classes are defined, each containing specific functionality. Objects of these classes are generated by the abstract factory to populate the client.

The following code shows the basic code of the abstract factory design pattern implemented using C#:

public class Client
{
    private AbstractProductA _productA;
    private AbstractProductB _productB;

    public Client(AbstractFactory factory)
    {
        _productA = factory.CreateProductA();
        _productB = factory.CreateProductB();
    }
}


public abstract class AbstractFactory
{
    public abstract AbstractProductA CreateProductA();

    public abstract AbstractProductB CreateProductB();
}


public class ConcreteFactoryA : AbstractFactory
{
    public override AbstractProductA CreateProductA()
    {
        return new ProductA1();
    }

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


public class ConcreteFactoryB : AbstractFactory
{
    public override AbstractProductA CreateProductA()
    {
        return new ProductA2();
    }

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


public abstract class AbstractProductA { }

public class ProductA1 : AbstractProductA { }

public class ProductA2 : AbstractProductA { }

public abstract class AbstractProductB { }

public class ProductB1 : AbstractProductB { }

public class ProductB2 : AbstractProductB { }

Example Abstract Factory

To show a simple example of the factory method design pattern in action, we will create two factories that generate the packaging and delivery document information described earlier. One factory will be responsible for creating delivery objects for standard parcels. The second will generate objects for delicate parcels. To keep the examples small, no functionality will be included within the classes unless it relates directly to the design pattern. The only change to the core pattern is the addition of two properties in the Client class to provide public access to the two generated objects.

public class Client
{
    private Packaging _packaging;
    private DeliveryDocument _deliveryDocument;

    public Client(PurchaseFactory factory)
    {
        _packaging = factory.CreatePackaging();
        _deliveryDocument = factory.CreateDeliveryDocument();
    }

    public Packaging ClientPackaging
    {
        get { return _packaging; }
    }

    public DeliveryDocument ClientDocument
    {
        get { return _deliveryDocument; }
    }
}


public abstract class PurchaseFactory
{
    public abstract Packaging CreatePackaging();

    public abstract DeliveryDocument CreateDeliveryDocument();
}


public class StandardPurchaseFactory : PurchaseFactory
{
    public override Packaging CreatePackaging()
    {
        return new StandardPackaging();
    }

    public override DeliveryDocument CreateDeliveryDocument()
    {
        return new PostalLabel();
    }
}


public class DelicatePurchaseFactory : PurchaseFactory
{
    public override Packaging CreatePackaging()
    {
        return new ShockProofPackaging();
    }

    public override DeliveryDocument CreateDeliveryDocument()
    {
        return new CourierManifest();
    }
}


public abstract class Packaging { }

public class StandardPackaging : Packaging { }

public class ShockProofPackaging : Packaging { }

public abstract class DeliveryDocument { }

public class PostalLabel : DeliveryDocument { }

public class CourierManifest : DeliveryDocument { }

Testing the Abstract Factory

The example implementation of the abstract factory pattern can be tested by adding the above classes to a console application named "AbstractFactoryPattern" and by adding the following code to the Main method. This code creates two Client objects, each being passed a different type of factory in its constructor. By outputting the types of the generated objects, accessed through the Client's properties, you can see that the factories have created a different pair of object types in each case.

PurchaseFactory spf = new StandardPurchaseFactory();
Client standard = new Client(spf);
Console.WriteLine(standard.ClientPackaging.GetType());
Console.WriteLine(standard.ClientDocument.GetType());

PurchaseFactory dpf = new DelicatePurchaseFactory();
Client delicate = new Client(dpf);
Console.WriteLine(delicate.ClientPackaging.GetType());
Console.WriteLine(delicate.ClientDocument.GetType());

/* OUTPUT

AbstractFactoryPattern.StandardPackaging
AbstractFactoryPattern.PostalLabel
AbstractFactoryPattern.ShockProofPackaging
AbstractFactoryPattern.CourierManifest

*/
Link to this Page4 August 2008
RSS RSS Feed