Design Pattern articles in this series are listed below:

Design Patterns - An Overview
Design Patterns – Using the Strategy Pattern in C#
Design Patterns – Using the Singleton Pattern in C#
Design Patterns – Using the Adapter Pattern in C#
Design Patterns - Using the Facade Pattern in C#
Design Patterns - Using the Composite Pattern in C#
Design Patterns - Using the Decorator Pattern in C#
Design Patterns - Using the Abstract Factory Pattern in C#
Design Patterns – Using the Builder Pattern in C#
Design Patterns - Using the Observer Pattern in C# (Events and Delegates)
Design Patterns – Using the Chain of Responsibility Pattern in C#
Design Patterns – Using the State Pattern in C#
Design Patterns – Which to use When? Take the Quiz!

What is an Abstract Factory Pattern?

The Abstract Factory Pattern provides an interface for creating families of related objects without specifying their concrete classes. The Abstract Pattern makes sure that the client does not know anything about the objects being created. The pattern hides the implementation of the product definitions and their class names and the only way the client can create a product is through the factory.

Why can’t we just use the new operator for creating objects?

In C#, an object can be created using the new operator.

Television television = new Television();

So, why do we need a design pattern to create objects? Why can’t we just use the new operator?The new operator is considered harmful because it tightly couples the object creation. For building solutions that are scalable, easier to maintain and flexible, it is necessary to abstract the creation process and give the client an ability to only "request" for an object to be created and not the ability to “create" an object.

How is the Abstract Factory Pattern implemented?

Though the implementation is relatively simpler, there are a large number of players in this design pattern. Generally, there are 2 class hierarchies. One for the Factory and the other for the Product.

The following components make up the Abstract Factory Pattern

1. Abstract Factory - An abstract class that has abstract "Create" methods for Products

2. Concrete Factory 1..n - Concrete class implementations of the Abstract Factory.

3. Abstract Product - An abstract class for different types of Products

4. Concrete Product 1..n - Concrete class implementation of different types of Products

5. Client - The client uses the factory to generate a family of related objects

Let’s take a look at an example to make this pattern easier to understand. ABC Inc., is a company that rewards loyalty of it's customers by giving free televisions based on their membership type. ABC Inc., decides to use the following algorithm for rewarding it's customers:

1. If a customer is a Silver Member, he/she is entitled to receive a Samsung 42" TV

2. If a customer is a Gold Member, he/she is entitled to receive a Sony 55" TV

When it’s time to reward the customers, ABC Inc., places orders with the TV manufacturers (Samsung and Sony) to manufacture and ship televisions. Samsung and Sony manufactures the following products:

1. Televisions of different sizes (42” or 55”)

2. DVD Players

Note that for simplicity, we will consider one Product tree (for Televisions). We will not implement the DVD Player related classes although it would be very similar to the implementation for Televisions. First, let's look at the Abstract Factory class.

//Abstract Factory Class
public abstract class TVFactory
{
    public abstract PlasmaTV CreateTV(TVSize tvSize);
    //public abstract DVDPlayer CreateDVDPlayer();	(Not implemented for simplicity)
}

Samsung and Sony concrete factories derive from the TVFactory. The CreateTV() method instantiates an object of the corresponding Products class.

//Concrete Factory Class 1
public class SonyFactory : TVFactory
{
    public override PlasmaTV CreateTV(TVSize tvSize)
    {
        return new SonyTV(tvSize);
    }

    //For DVD Players, we would have a similar implementation for CreateDVD() method
}

//Concrete Factory Class 2
public class SamsungFactory : TVFactory
{
    public override PlasmaTV CreateTV(TVSize tvSize)
    {
        return new SamsungTV(tvSize);
    }

    //For DVD Players, we would have a similar implementation for CreateDVD() method
}

In the Product class hierarchy, we will first define an abstract class called PlasmaTV (the Abstract Product Class). All Plasma TVs have a LCD Display. We define an abstract method called AddDisplay() that the concrete Product classes override.

//Abstract Product
public abstract class PlasmaTV
{
    public abstract void AddDisplay(TVSize tvSize);
}

Finally, let's look at the Concrete Product classes for Televisions. The constructors call the AddDisplay() method that adds either a 55inch display or the 42inch display and completes manufacturing the television. If we were to implement the DVDPlayer related classes, we would have had another class hierarchy with an abstract class for DVDPlayer and it’s corresponding concrete class implementations.

How does the client use the set of classes we created? Through the concrete factory classes. The client never instantiates the product directly, instead it uses the factory classes that encapsulates the product creation.

In our example, the client has a dictionary of customers and their membership type. When it's time for rewarding the customers, it iterates through the Dictionary collection and makes a determination on whether the customer receives a Sony 55" TV or a Samsung 42" TV

namespace AbstractFactoryPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            //Create a list of customers
            Dictionary<string, MemberType> dictCustomers = new Dictionary<string, MemberType>();
            dictCustomers.Add("Jane", MemberType.SilverMember);
            dictCustomers.Add("Joe", MemberType.GoldMember);
            dictCustomers.Add("Bob", MemberType.SilverMember);

            InitializeLoyaltyProgram(dictCustomers);
        }

        private static void InitializeLoyaltyProgram(Dictionary<string, MemberType> dictCustomers)
        {
            foreach (KeyValuePair<string, MemberType> kvp in dictCustomers)
            {
                if (kvp.Value == MemberType.SilverMember)
                {
                    //Silver Member gets a Samsung 42inch TV
                    TVFactory tvFactory1 = new SamsungFactory();
                    Console.Write(String.Format("For {0} - ", kvp.Key));
                    tvFactory1.CreateTV(TVSize.FortyTwoInch);
                    Console.WriteLine("");
                }

                if (kvp.Value == MemberType.GoldMember)
                {
                    //Gold Member gets a Sony 55inch TV
                    TVFactory tvFactory2 = new SonyFactory();
                    Console.Write(String.Format("For {0} - ", kvp.Key));
                    tvFactory2.CreateTV(TVSize.FiftyFiveInch);
                    Console.WriteLine("");
                }
            }

        }
    }
}

The output is shown in the screenshot below

image

For the sake of completeness, the code snippets for the enums are as shown below.

public enum MemberType
{
    SilverMember,
    GoldMember
}

public enum TVSize
{
    FortyTwoInch,
    FiftyFiveInch
}

Benefits and Drawbacks of Abstract Factory Pattern

This pattern provides the client with a simple interface and encapsulates the complex object creation. As such, when the implementation of a product changes, the client does not need to change. It also imposes constraints on product families. However, one of the drawback of the Abstract Factory Pattern is that adding new kinds of products to an existing factory will involve not only updating the factory but also the concrete classes.

Physical Model – Class Diagram

image

Conclusion

The Intent of the Abstract Factory Pattern is to offer an interface for creating a family of related objects without explicitly specifying their classes. This pattern should be used when a family of products is designed to work only all together or when the system needs to be independent from the way the products it works with are created.

Check out other articles in the Design Pattern series on this site. You can also follow DotNetCube on Twitter or subscribe to the RSS feed.

Retweetkick it on DotNetKicks.com