C# Corner
The Factory Pattern in .NET (Part 3)
C# Corner columnist Patrick Steele concludes his exploration of factory patterns in .NET.
In
part 1 of this series, I began exploring software factory patterns and how they can be used to enable more flexible application architecture.
Part 2 looked at abstract factories and delegate-based factories and how they can be used to support customizations. In this final installment, I'll clarify some of the concepts introduced in the first article, look at how other software is using the factory pattern and address some comments from the first two parts.
Picking Your Factory
In the first article of this series, I laid the foundation of how using a factory can help de-couple your code from knowing what type of object the factory is creating. Your code simply asks the factory to "build something" and it gets back an object that it can use.
The second article talked about abstract factories. The provider of an abstract factory usually provides a default implementation. But if you decided to take advantage of the pattern and create your own factory, you need to let your application know which factory to use -- that part has been missing.
How you pick your factory really comes down to an "it depends" situation. In a super-simple case, you can add a fully-qualified type name to your app.config file which would define which factory to use. For example:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="factoryType" value="PickingYourFactory.Factories.CustomFactoryClass, PickingYourFactory"/>
</appSettings>
</configuration>
In the example above, there is a "CustomFactoryClass" in the "PickingYourFactory.Factories" namespace which is found in the "PickingYourFactory" assembly. Creating this factory is accomplished with this code:
var factoryTypeName = ConfigurationManager.AppSettings["factoryType"];
var factory = Activator.CreateInstance(
Type.GetType(factoryTypeName))as IFactoryInterface;
In this example, the extension point for creating your own factory was any object that implemented the IFactoryInterface. Just replace the type name in app.config with your custom factory implementation and you're all set.
The code above would probably be used at the beginning of an application's lifecycle. But you could just as easily obtain the factoryTypeName by different means. Perhaps there's a flag in your application that would determine which factory to use -- or maybe something stored in a database. It really depends on your architecture.
Also, many applications today use IoC containers to manage object lifetimes and dependency injection (See "Inversion of Control Patterns for the Microsoft .NET Framework, Visual Studio Magazine, August 2010). If you need to use factories to instantiate your components (instead of having the IoC container do it), most containers will have extension points to allow this. If you're using an IoC container, check their documentation.
Don't Limit Your Factory
One thing you want to try and avoid in your factories is limiting what they can create. One example of this limitation is defining an enum that determines what factory to use. In our example from part 1, we had an ITextProcessor that we obtained via an ITextProcessorFactory. We could set up some code to determine which ITextProcessorFactory to use. That code might look something like this:
enum TextProcessorType
{
File,
FTP,
Azure
}
public ITextProcessorFactory CreateTextProcessor(
TextProcessorType processorType)
{
if( processorType == TextProcessorType.File)
{
return new FileTextProcessor();
}
// etc...
}
But this limits us to only three text processor types. We can't assume this will be able to suit our needs for everything that may happen in the future. If we ever needed to support a new type of text processor (and thus, a new factory), we would have to create a new enum type along with the new factory and recompile all of our code that references the enum. By sticking to a type name, you make the extension point much more flexible.
The Factory Pattern in Practice
There are many places in the .NET framework as well as popular open source projects that use the factory pattern to enable extensibility in their architecture. These samples should help show you the various use cases that may help you in deciding if the factory pattern is a good fit for a particular portion of your applications or libraries.
ASP.NET MVC
The ASP.NET MVC framework is used for creating Web applications that employ the MVC (Model-View-Controller) pattern. In part 2 of this article, we showed how the controller factory that ships with ASP.NET MVC can be subclassed to allow controller creation to be handled by an IoC container (instead of simply creating a brand new instance of the controller via Activator.CreateInstance).
The ASP.NET MVC framework doesn't have to have any knowledge of IoC containers, databases or anything else, it just tells the configured controller factory to create a controller for a specific controller type. The type of factory used by the ASP.NET MVC runtime is configured via the web.config file.
nHibernate
nHibernate is a .NET port of the popular Java ORM (Object Relation Mapper) "hibernate." The basic unit of work in most any nHibernate operation is a Session. The Session contains all sorts of configuration information such as the database connection string as well as the table and column mappings.
However, the hibernate/nHibernate developers knew that they couldn't think of every possible scenario for Session use so they expose a SessionFactory, which is in charge of creating a Session. By creating your own SessionFactory, you could create a custom Session object that, for example, uses its own database connection -- instead of creating a new connection using the connection string nHibernate is configured to use. The key here is that the creation of a Session is not buried inside nHibernate. It's exposed via a replaceable and extensible SessionFactory.
Castle Windsor IoC Container
The Castle Windsor IoC container contains a facility called the Typed Factory Facility (in Windsor, a Facility is simply a way to extend the container). The Typed Factory Facility actually generates (at runtime) an abstract factory for you to allow components to pull in their dependencies from the container without knowing the dependencies are actually in the container. In other words, if your factory interface looks like this:
public interface IFactoryInterface
{
IWidget CreateWidget();
}
Your container would be configured for which class implements IWidget. You would also tell Windsor that it should provide an abstract factory implementation of IFactoryInterface. This means that when a component gets a reference to the IFactoryInterface and calls a method (like CreateWidget), the container's generated factory will look inside the container to determine what it should return for an IWidget. Very elegant and you don't need to write a factory that would do nothing but call Windsor's "kernel.Resolve" all the time.
ADO.NET
Even the .NET Framework itself utilizes the factory pattern! The ADO.NET class DbProviderFactory is an abstract factory that represents a set of methods ADO.NET will use to talk to provider-specific implementations.
ADO.NET provides base classes for a DbConnection, a DbCommand and many other classes for database interaction. Each provider (Microsoft SQL Server, Oracle, MySQL, etc... ) creates their own implementation of these base classes -- such as "SqlConnection," "SqlCommand," "OracleConnection," etc.... Then, each provider creates their own subclass of the DbProviderFactory, which will return the provider specific implementations. This allows Microsoft to write a rich database framework without having to have knowledge about how the low-level implementation of each provider needs to be handled. Support for new databases can be added without updating the .NET Framework: simply create the provider-specific classes and then a provider-specific factory and you're good to go!
Comment Feedback
Feedback is always important to me and there are a couple of things I wanted to address.
First, there was a typo in the sample code when the FTPSiteProcessor was defined. In part 1, the code was listed as:
class ITextProcessor : ITextProcessor
The class should have been defined as:
class FTPSiteProcessor : ITextProcessor
Finally, some of the other comments focused on the lack of implementation details for using or selecting a factory. In the small scope of an online article, it's always difficult determining how much code is "enough" to convey an idea or concept. Hopefully, this final article in the series has addressed those issues by showing you examples of the factory pattern in use today.
About the Author
Patrick Steele is a senior .NET developer with Billhighway in Troy, Mich. A recognized expert on the Microsoft .NET Framework, he’s a former Microsoft MVP award winner and a presenter at conferences and user group meetings.