Using Factory method pattern in .Net

A common answer to a question about benefits of using design patterns is "Design patterns are used to provide an object oriented based solution to known problems.". This answer is correct (kind of), you see, there are other reasons (motivations) to use and apply design patterns.Design patterns are also used as tools developers and architects use to solve/overcome common programming challenges regarding re-usability and maintainability.

Just like anything we used in our daily lives, there always a benefit and a price for using design pattern. All patterns' benefits can be found in pattern's motivation (reasons to apply) which is part of the pattern's definition, however, the price is usually hidden in the pattern's consequence, we have to dig deep to find it. Because of that, it is paramount that we understand both pattern's benefits and consequence prior to making any commitment to using a specific one.

The factory method pattern

The motivation behind the factory method pattern is clear, it simply builds objects when the object hierarchy is clearly defined. Often, the object's building process is aided by using parameters to determine the type of object the client is requesting, however, this is not always required.

When to use a factory pattern:
  1. When your object hierarchy is clearly defined
  2. When we want to separate the creation of an object from its representation
  3. When the client (any client) doesn't know the concrete type to initialize at runtime
  4. When the object's creating logic is complicated
Use case:

To further examine the benefits of using the factory method pattern, we will create a use case and work through the requirements using a windows form application. Our client is an HR organization with the following easy requirements for an HR application:

  1. Needs to be able to create employee records (Manager, SalesPerson and HelpDeskAnalyst).
  2. All employees have a Title and vacation days (for the purpose of this demo, all human rights and labor laws will be violated as we are not paying these employees).
  3. HR personnel need to be able to enter an employee title to create the employee.
  4. Managers have 4 week vacation days, SalesPersons have a 2 week vacation days and HelpDeskAnalyst employees get 3 week vacation days.
  5. The client will need to be able to add additional employee types as the business grows.
The no thought process solution to solving our domain problem:

As mentioned above, the requirements are rudimentary at best. The easiest way to comply with the clients requirements is by writing the following solution:

For this demo, we will create a windows form project and add the following classes

  1. The base abstract Employee class (you can choose to create an interface if you like)

    public abstract class Employee
    {
       public  virtual string Title { get{ return "Employee";}}
       public  abstract int VacationDays { get; }
     
    }
  2. The HelpDeskAnalyst class (note that it inherits from Employee)

    public class HelpDeskAnalyst : Employee
     {
         public override  string Title
         {
             get
             {
                 return "Help Desk Analsty";
             }
         }
         public override int VacationDays
         {
             get
             {
                 return 15;
             }
         }
        
     }
  3. The Manager class

    public class Manager : Employee
     {
         public  override string Title
         {
             get
             {
                 return "Manager";
             }
         }
         public override int VacationDays
         {
             get
             {
                 return 20;
             }
         }
     }
  4. The SalesPerson class

    public class SalesPerson : Employee
     {
         public override string Title
         {
             get
             {
                 return "Sales Person";
             }
         }
         public override  int VacationDays
         {
             get
             {
                 return 10;
             }
         }
     }
  5. Finally, the client code (used inside a click event)

    private void CreateButton_Click(object sender, EventArgs e)
           {
               var userInput = UserInputTextBox.Text.ToLowerInvariant();
               Employee employee;
               switch (userInput)
               {
                   case "manager":
                       employee = new Manager();
                       break;
                   case "helpdeskanalyst":
                       employee = new HelpDeskAnalyst();
                       break;
                   case "salesperson":
                       employee = new SalesPerson();
                       break;
                   default:
                       employee = null;
                       break;
               }
               Display(employee, userInput);
           }
           void Display(Employee employee, string userInput)
           {
               DisplayLabel.Text = employee == null ? "failed to create employee using provided title" + userInput : string.Format("Employee Title is {0} and Employee Vacation Days are {1}", employee.Title, employee.VacationDays);
           }

So what’s wrong with this implementation?

Some may argue, nothing. The code builds and fulfills the client requirements and they would be right if we were living in procedural programming age. But we are aiming to apply OOP principles and create reusable components without any of this tight coupling.

Factories to the rescue!

We will refactor our existing solution to use a factory to create the employee and apply OOP SOLID principles. First, we will create a factory interface (IEmloyeeFactory), this interface will contain a single method returning an employee object.

Here's what a factory method UML should look like

The factory Interface and implementation:

public interface IEmployeeFactory
 {
     Employee CreateEmployee(string title);
 }
 public class EmployeeFactory : IEmployeeFactory
 {
     private static readonly ConcurrentDictionary<string, Type> dictionary = new ConcurrentDictionary<string, Type>();
     static EmployeeFactory()
     {
         var employeeSubTypes = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsSubclassOf(typeof(Employee)));
         foreach (var type in employeeSubTypes)
         {
             dictionary.TryAdd(type.Name.ToLowerInvariant(), type);
         }
     }
     public  Employee CreateEmployee(string title)
     {
         var result =  (dictionary.Where(e => String.Compare(e.Key, title, false) == 0).Select(e => e.Value)).FirstOrDefault();
         return result != null ? (Employee) Activator.CreateInstance(result) : null;
     }
 }

If you don't understand the reason behind initializing the dictionary in a static constructor, read the post titled "Understanding Constructors in .Net"

After adding the IEmployeeFactory interface and implementing it, our client (the button's click event) looks like this:

private void CreateButton_Click(object sender, EventArgs e)
    {
        var userInput = UserInputTextBox.Text.ToLowerInvariant();
        IEmployeeFactory factory = new EmployeeFactory();
        var emp = factory.CreateEmployee(userInput);
      Display(emp, userInput);
    }
What did we achieve?

By redesigning our solution to use a factory pattern approach we achieved the following:

  1. Loose coupling, our client doesn't know what kind of employee is used.
  2. Open Closed Principle doesn't need to be violated as we can extend our factory with modifying the current ones.
  3. Extensibility, we can add additional employee types without having to modify any of the existing code and our application will work.
Consequences (disadvantages) of factory method pattern

As mentioned in the beginning of the article, there are advantages and disadvantages to using any pattern, using the factory method has the following disadvantages

  1. A factory method will be required for each type of object we create
  2. Inheritance hierarchy can get too deep which will lead to tight coupling between the factories and the objects family they are creating

For any questions of feedback, hit the comment box or email me using the contact page

FactoryPatternDemo.zip (56.11 kb)

Comments (1) -

Just wanted to say thank you for your work.

Add comment