Design Pattern How-To: Factory

Update: this blog has been moved to http://brandonzeider.me/2010/design-patterns/design-pattern-how-to-factory/

Design patterns are reusable solutions to common problems in software development. Design patterns have been around for quite some time, but really didn't pick up steam in the software development community until 1994, when the "Gang of Four" (GoF) released Design Patterns: Elements of Reusable Object-Oriented Software. In this book, 23 design patterns are described, grouping them into three categories: Creational, Structural, and Behavioral, and is highly recommended reading for anyone interested in software development.

In this post we will explore one of the most common creational patterns, the Factory. Factories are one attempt to solve the problem of creating objects, where the construction logic is encapsulated in the factory and abstracted from the rest of the system. When class A creates an instance of class B, A and B are tightly coupled via that constructor logic. Factories allow us to remove that coupling. We will cover a simple factory, a more advanced implementation using Generics, and an Abstract Factory. For our examples, we will have a simple use case of Customer and Employee classes that both derive from a User base class. This use case will be overly simplified for the purpose of demonstration.

Simple Factory

Let's say we have a User object with the following definition:

namespace BusinessObjects.Simple
{
	public abstract class User
	{
		public string FirstName { get; set; }

		public string LastName { get; set; }

		public abstract string ID();
	}
}

And the following concrete objects:

namespace BusinessObjects.Simple
{
	public sealed class Employee : User
	{
		public int EmployeeID { get; set; }

		public override string ID() { return "Employee ID: " + EmployeeID; }
	}

	public sealed class Customer : User
	{
		public int CustomerID { get; set; }

		public override string ID() { return "Customer ID: " + CustomerID; }
	}
}

In this example, the Employee and Customer objects are unquely identified by the EmployeeID and CustomerID. Next we can create factories for these objects. First, the base factory, with an abstract method CreateUser. This method must be implemented by concrete factories. Notice that the CreateUser method returns an object of type User, which is the base object for Employee and Customer.

namespace BusinessObjects.Simple.Factories
{
	public abstract class UserFactory
	{
		public abstract User CreateUser(int id);
	}
}

Next, the concrete factories, with the CreateUser implementation. This method encapsulates the constructor logic for that object.

namespace BusinessObjects.Simple.Factories
{
	public sealed class EmployeeFactory : UserFactory
	{
		public override User CreateUser(int id)
		{
			return new Employee()
			{
				EmployeeID = id
			};
		}
	}

	public sealed class CustomerFactory : UserFactory
	{
		public override User CreateUser(int id)
		{
			return new Customer()
			{
				CustomerID = id
			};
		}
	}
}

Now we can test our factories:

private void SimpleFactoryTest()
{
        List<User> users = new List<User>();
        EmployeeFactory employeeFactory = new EmployeeFactory();
        CustomerFactory customerFactory = new CustomerFactory();

        //Create employees
        users.Add(employeeFactory.CreateUser(1));
        users.Add(employeeFactory.CreateUser(2));
        users.Add(employeeFactory.CreateUser(3));
        users.Add(employeeFactory.CreateUser(4));
        users.Add(employeeFactory.CreateUser(5));

        //Create customers
        users.Add(customerFactory.CreateUser(6));
        users.Add(customerFactory.CreateUser(7));
        users.Add(customerFactory.CreateUser(8));
        users.Add(customerFactory.CreateUser(9));
        users.Add(customerFactory.CreateUser(10));

        foreach (User user in users)
        {
                OutputListBox.Items.Add(user.ID());
        }
}

Generics Implementation

With Generics, our implementation takes significantly less code. First, we add constructors to the Customer and Employee objects:

public Customer(int id) { CustomerID = id; }

public Employee(int id) { EmployeeID = id; }

Then we create the generic factory:

namespace BusinessObjects.Generic
{
	public class Factory<T>
	{
		public T Create(params object[] parameters)
		{
			return (T)Activator.CreateInstance(typeof(T), parameters);
		}
	}
}

In this simple example, T represents the type of the object we are instantiating. We then have one method, Create, that accepts a parameter array. Using the Activator class, we create an instance of type T, which calls our constructor on the Customer and Employee objects. That's it! We can then test our factory:

private void GenericFactoryTest()
{
        List<User> users = new List<User>();
        Factory<Employee> employeeFactory = new Factory<Employee>();
        Factory<Customer> customerFactory = new Factory<Customer>();

        //Create employees
        users.Add(employeeFactory.Create(1));
        users.Add(employeeFactory.Create(2));
        users.Add(employeeFactory.Create(3));
        users.Add(employeeFactory.Create(4));
        users.Add(employeeFactory.Create(5));

        //Create customers
        users.Add(customerFactory.Create(6));
        users.Add(customerFactory.Create(7));
        users.Add(customerFactory.Create(8));
        users.Add(customerFactory.Create(9));
        users.Add(customerFactory.Create(10));

        OutputListBox.Items.Add("BEGIN GENERIC TEST");

        foreach (User user in users)
        {
                OutputListBox.Items.Add(user.ID());
        }

        OutputListBox.Items.Add("END GENERIC TEST");
}

Abstract Factory

Abstract factories are much the same as non-abstract factories, but do not use subclasses to determine which class is instantiated. The difference is very subtle, but once you see it in action, it becomes more clear. We'll use the same User, Customer and Employee objects as before. Next we'll create an interface for our factories called IFactory:

namespace BusinessObjects.Abstract
{
	public interface IFactory
	{
		User CreateUser(int id);
	}
}

Next we'll create a CustomerFactory and an EmployeeFactory:

namespace BusinessObjects.Abstract
{
	public class CustomerFactory : IFactory
	{
		#region IFactory Members

		public User CreateUser(int id)
		{
			return new Customer(id);
		}

		#endregion IFactory Members
	}

	public class EmployeeFactory : IFactory
	{
		#region IFactory Members

		public User CreateUser(int id)
		{
			return new Employee(id);
		}

		#endregion IFactory Members
	}
}

Now we're ready to test. This is where the difference between the factory pattern and the abstract factory pattern will become clear.

private void AbstractFactoryTest(bool createEmployee)
{
        IFactory factory = null;

        if (createEmployee)
        {
                factory = new BusinessObjects.Abstract.EmployeeFactory();
        }
        else
        {
                factory = new BusinessObjects.Abstract.CustomerFactory();
        }

        User user = factory.CreateUser(1);

        OutputListBox.Items.Add("BEGIN ABSTRACT TEST");
        OutputListBox.Items.Add(user.ID());
        OutputListBox.Items.Add("END ABSTRACT TEST");
}

In the example above, once the correct factory is determined, we call the CreateUser method defined in the interface, and that returns the correct object without specifying their concrete class.

Summary

As you can see factories are a way of encapsulating class construction and abstracting it from the rest of the system. These examples are very basic, but should give you an idea of how powerful the factory pattern can be. Use them in your project when you want to decouple object creation.

Download

FactoryExample.zip (74.38 kb)

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.

 

Bookmark and Share dotnetshoutout
Tags: ,
Categories: Design Patterns | Microsoft .NET

Permalink E-mail | Kick it! | DZone it! | del.icio.us Comments (2) Post RSSRSS comment feed

Comments

8/17/2010 9:13:18 PM #

Design Pattern How-To: Singleton

Design Pattern How-To: Singleton

Brandon Zeider's Blog

9/29/2010 9:29:56 PM #

Pingback from brandonzeider.me

Design Pattern How-To: Singleton | Brandon Zeider's Blog

brandonzeider.me