.NET Design Patterns: The Abstract Factory Pattern

Pattern Type: Creational

Intent

The intent of the abstract factory pattern is to leave the decision of the type of object to create up to the abstract being called. All the client needs to know is "I have a type of foo" and that "foo" implements each of the creational methods needed to hand a concrete class to the client of the pattern.

Description

The factory pattern is probably one of the most used design patterns in the C# and .NET environment. It can be seen everywhere from the ADO.NET database factory right through to the generation of different output types in ASP.NET.

The factory pattern is essentially used to create an object type to be consumed with each object type being created via a single method call. Sometimes, an extra parameter is passed in to decide on the type of object to create.

In the ADO.NET runtime, for example, a connection string is passed in; this connection string is used to determine the underlying database connector to create, an instance of which is then passed back. The returned object shares a common footprint with other abstract classes implemented in the same interface, and thus can be trusted to provide a 1 to 1 mapping of functionality irrespective of which database technology the underlying library is using.

The key to using a factory pattern effectively is to prevent the client and other outside factors from creating the class you want to use. This is often done by making the class constructor internal to the abstract parent and members of the abstract namespace that use it. By making the constructor internal, no external class can instantiate a new copy of the class, and thus it then has to be given to factory methods in the abstract base to create and hand off a concrete implementation.

Diagram

Factory1
Figure 1: The factory pattern

Client: This is the consumer requesting the concrete implementation provided by the abstract base

Abstract Product: Declares the known interface for products of the type supported by that abstract base

Product: Abstract implementations of the abstract product that match the base implementation

Abstract Factory: Main consumable base class that creates concrete versions of the various abstracted entities within the family

Concrete xxx: Concrete implementations of the actual products and related factories, responsible for the actual core objects returned by the abstract factory

Implementation in C#

Generally, you start with the actual abstract factory itself.

abstract class AbstractFactory
{
   public abstract AbstractProduct1 CreateProduct1();
   public abstract AbstractProduct2 CreateProduct2();
}

Following that are the abstract implementations of the various classes.

Note: I've not added any implementation to anything here because this is a purely object creation pattern.
abstract class AbstractProduct1
{
}

abstract class AbstractProduct2
{
}


class FirstProduct1 : AbstractProduct1
{
}

class FirstProduct2 : AbstractProduct2
{
}

class SecondProduct1 : AbstractProduct1
{
}

class SecondProduct2 : AbstractProduct2
{
}

As you can see, we have two parent abstract classes (one for each product) from which the four final abstract classes are derived.

Once you have the various abstracted classes in place, you can begin on the concrete implementations.

class FirstProductConcreteFactory: AbstractFactory
{
   public override AbstractProduct1 CreateProduct1()
   {
      return new FirstProduct1();
   }

   public override AbstractProduct2 CreateProduct2()
   {
      return new FirstProduct2();
   }
}

class SecondProductConcreteFactory : AbstractFactory
{
   public override AbstractProduct1 CreateProduct1()
   {
      return new SecondProduct1();
   }

   public override AbstractProduct2 CreateProduct2()
   {
      return new SecondProduct2();
   }
}

Followed, finally, by the client that will ultimately use them.

class Client
{
   private AbstractProduct1 _myFirstProduct;
   private AbstractProduct2 _mySecondProduct;

   public Client(AbstractFactory myFactory)
   {
      _myFirstProduct = myFactory.CreateProduct1();
      _mySecondProduct = myFactory.CreateProduct2();
   }

}

Once you have a client ready to use, you can create and make use of the construction chain by using something like the following:

AbstractFactory firstProductFactory =
   new FirstProductConcreteFactory();
Client firstProductClient = new Client(firstProductFactory);

AbstractFactory secondProductFactory =
    new SecondProductConcreteFactory();
Client secondProductClient = new Client(secondProductFactory);


About the Author

Peter Shaw

As an early adopter of IT back in the late 1970s to early 1980s, I started out with a humble little 1KB Sinclair ZX81 home computer. Within a very short space of time, this small 1KB machine became a 16KB Tandy TRS-80, followed by an Acorn Electron and, eventually, after going through many other different machines, a 4MB, ARM-powered Acorn A5000. After leaving school and getting involved with DOS-based PCs, I went on to train in many different disciplines in the computer networking and communications industries. After returning to university in the mid-1990s and gaining a Bachelor of Science in Computing for Industry, I now run my own consulting business in the northeast of England called Digital Solutions Computer Software, Ltd. I advise clients at both a hardware and software level in many different IT disciplines, covering a wide range of domain-specific knowledge—from mobile communications and networks right through to geographic information systems and banking and finance.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date