Note: This is part of an ongoing series introducing patterns at the Tampa C# Meetup.
Purpose
The factory pattern, formally called the** Abstract Factory Pattern**, abstracts the creation of a concrete class.
Basics
Using this pattern requires 4 things.
- A base class or interface that the created concrete classes derive from
- An abstract class or interface base with a method that has a return type signature from #1
- One or more concrete classes derived from the type in #1
- A number of concrete creation classes derived from the type in #2 with an implementation to the creation method returning a concrete class
Derivatives
It is possible to implement this pattern with using the creation class, and instead using a method, or in .NET a delegate. This is sometimes referred to as the Factory Method Pattern.
Abstract Factory Implementation
Since I am very tired of the animals or cars class hierarchies, I chose televisions for my hierarchy.
Base Class for Concrete Types
{% gist dbuksbaum/d59d0726000f623c0114 Television.cs %}
Interface for the Creation Type
{% gist dbuksbaum/d59d0726000f623c0114 ITelevisionCreator.cs %}
Concrete Types
{% gist dbuksbaum/d59d0726000f623c0114 LCD.cs %}
Concrete Creator Classes
{% gist dbuksbaum/d59d0726000f623c0114 CreatorLEDTelevision.cs %}
Test Case
I have created a simple method that will take the interface to the creation class, creates the type, and calls a few methods.
private static void TestTelevision(ITelevisionCreator tvCreator)
{
var tv = tvCreator.CreateTelevision();
tv.TurnOn();
tv.SetChannel(100);
tv.TurnOff();
}
And here is how I call the test method for each factory.
Console.WriteLine("Using Abstact Factory");
TestTelevision(new CreatorLCDTelevision());
TestTelevision(new CreatorLEDTelevision());
TestTelevision(new CreatorPlasmaTelevision());
Factory Method Implementation
Since I seem to run into the factory method model more often, I wanted to show the implementation as it compares to the Abstract Factory Pattern. The key change is that we require a creation method instead of a creation class.
Test Case with Delegates
Console.WriteLine("Using Delegate Creator");
TestTelevision(new CreatorLCDTelevision().CreateTelevision);
TestTelevision(new CreatorLEDTelevision().CreateTelevision);
TestTelevision(new CreatorPlasmaTelevision().CreateTelevision);
As you can see, I am still using the concrete creation classes, but now passing in the creation method as a delegate.
Here is the code for the test case.
private static void TestTelevision(Func<Television> tvCreator)
{
var tv = tvCreator();
tv.TurnOn();
tv.SetChannel(100);
tv.TurnOff();
}
As you notice, there are only two changes.
- Change 1 – The signature for the method entry changes from taking the interface to taking a delegate that returns the Television base class (line 1)
- Change 2 – The actual creation call is now just a delegate method call instead of instance method call (line 2)
While this is not a significant change in the amount of code or function, it increases the flexibility. Let me show you some of that flexibility.
Console.WriteLine("Using Lambda Creator");
TestTelevision(() => new LCD());
TestTelevision(() => new LED());
TestTelevision(() => new Plasma());
Conclusion
In the final test case of the **Factory Method Pattern **version, the creation classes have been completely replaced by lambda delegates. This eliminates a few types, specifically 4 in this case. Where this becomes very useful, is now it is possible to store those delegates in a collection, perhaps a Dictionary, and select it based on some input criteria, such as a type id. This creates a basic jump table from a type to a method to create that type. This is the basic functionality needed for an Inversion of Control container.
As I mentioned earlier on, this pattern is used heavily in many frameworks. One example is in Caliburn.Micro. Here is a the ElementConvention.cs source:
The ElementConvention class provides two factories, GetBindableProperty and CreateTrigger. It uses a C# field to replace these factories with user defined model using simple assignment, and the remainder of the Caliburn.Micro framework will go to this class use those factories.
The reason I consider this more flexible than the Abstract Factory Pattern, is that I do not need to create a creation base class, or any of the concrete creation classes. It is replaced by the Func generic delegate, and a delegate implementation based on a lambda or a instance method or a static class method.
As a reminder, these Patterns 101 posts are just meant to be quick example of commonly used patterns as implemented in C#. Please feel free to suggest patterns of interest of you, or even use cases you would like to see. Of course, you can just drop into the Tampa C# Meetup as I present these posts for our Patterns 101 segment.