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
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);