Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

Factory Method Design Pattern

Suggested Videos
Part 6 - Static Class vs Singleton - Text - Slides
Part 7 - Exception Logging using Singleton Design Pattern - Text - Slides
Part 8 - Factory Design Pattern Introduction - Text - Slides

In this tutorial we will learn
  1. Simple Factory
  2. Factory Method Pattern Implementation


Recap Simple Factory
  1. Simple factory abstracts the creation details of the product
  2. Simple factory refers to the newly created object through an interface
  3. Any new type creation is handled with a change of code in the factory class and not in the client code
public class EmployeeManagerFactory
{
    public IEmployeeManager GetEmployeeManager(int employeeTypeID)
    {
        IEmployeeManager returnValue = null;
        if (employeeTypeID == 1)
        {
            returnValue = new PermanentEmployeeManager();
        }
        else if (employeeTypeID == 2)
        {
            returnValue = new ContractEmployeeManager();
        }
        return returnValue;
    }
}



Factory Representation
Simple factory vs Factory method

From the above diagram, Factory representation block in the simple factory is replaced with Abstract Creator which further creates Concrete Creator A and Concrete Creator B Products providing another level of abstraction.

Factory Method Pattern Example

Business Requirement
  1. Differentiate employees as permanent and contract and segregate their pay scales as well as bonus based on their employee types.  ( We have achieved this using simple factory in Part 8 of the Design Patterns tutorial)
  2. Calculate Permanent employee house rent allowance
  3. Calculate Contract employee medical allowance
Steps to solve the above business requirement

Step 1: Add HouseAllowance and MedicalAllowance to the existing Employee table.

CREATE TABLE [dbo].[Employee] (
    [Id]               INT          IDENTITY (1, 1) NOT NULL,
    [Name]             VARCHAR (50) NOT NULL,
    [JobDescription]   VARCHAR (50) NOT NULL,
    [Number]           VARCHAR (50) NOT NULL,
    [Department]       VARCHAR (50) NOT NULL,
    [HourlyPay]        DECIMAL (18) NOT NULL,
    [Bonus]            DECIMAL (18) NOT NULL,
    [EmployeeTypeID]   INT          NOT NULL,
    [HouseAllowance]   DECIMAL (18) NULL,
    [MedicalAllowance] DECIMAL (18) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_Employee_EmployeeType] FOREIGN KEY ([EmployeeTypeID]) REFERENCES [dbo].[Employee_Type] ([Id]) ); 

Step 2: Open EmployeePortal.edmx under the Models folder of the solution and update the model from the database (Right click on the model designer and choose update from database option) 

Step 3: Create FactoryMethod folder under existing Factory folder and add BaseEmployeeFactory class. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Web.Managers;
using Web.Models;

namespace Web.Factory.FactoryMethod
{
    public abstract class BaseEmployeeFactory
    {
        protected Employee _emp;
        public BaseEmployeeFactory(Employee emp)
        {
            _emp = emp;
        }
        public Employee ApplySalary()
        {
            IEmployeeManager manager = this.Create();
            _emp.Bonus = manager.GetBonus();
            _emp.HourlyPay = manager.GetPay();
            return _emp;
        }
        public abstract IEmployeeManager Create();
    }
} 

Step 4: Create ContractEmployeeFactory class under FactoryMethod folder. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Web.Managers;
using Web.Models;

namespace Web.Factory.FactoryMethod
{
    public class ContractEmployeeFactory : BaseEmployeeFactory
    {
        public ContractEmployeeFactory(Employee emp) : base(emp)
        {
        }

        public override IEmployeeManager Create()
        {
            ContractEmployeeManager manager = new ContractEmployeeManager();
            _emp.MedicalAllowance = manager.GetMedicalAllowance();
            return manager;
        }
    }
}

Step 5: Create PermanentEmployeeFactory class under FactoryMethod folder. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Web.Managers;
using Web.Models;

namespace Web.Factory.FactoryMethod
{
    public class PermanentEmployeeFactory : BaseEmployeeFactory
    {
        public PermanentEmployeeFactory(Employee emp) : base(emp)
        {
        }

        public override IEmployeeManager Create()
        {
            PermanentEmployeeManager manager = new PermanentEmployeeManager();
            _emp.HouseAllowance = manager.GetHouseAllowance();
            return manager;
        }
    }
}

Step 6: Create EmployeeManagerFactory class under FactoryMethod folder and add new Method CreateFactory which returns BaseEmployeeFactory.

CreateFactory method is responsible to return base factory which is the base class of Permanent and Contract Factories. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Web.Models;

namespace Web.Factory.FactoryMethod
{
    public class EmployeeManagerFactory
    {
        public BaseEmployeeFactory CreateFactory(Employee emp)
        {
            BaseEmployeeFactory returnValue = null;
            if(emp.EmployeeTypeID ==1)
            {
                returnValue = new PermanentEmployeeFactory(emp);
            }
            else if (emp.EmployeeTypeID ==2)
            {
                returnValue = new ContractEmployeeFactory(emp); 
            }
            return returnValue;
        }
    }
} 

Step 7: Now, integrate the FactoryMethod in the EmployeesController’s Create method and replace the existing logic of simple factory method as stated below.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,JobDescription,Number,Department,HourlyPay,Bonus,EmployeeTypeID")] Employee employee)
{
    if (ModelState.IsValid)
    {
        BaseEmployeeFactory empFactory =
                    new EmployeeManagerFactory().CreateFactory(employee);
        empFactory.ApplySalary();
        db.Employees.Add(employee);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    ViewBag.EmployeeTypeID = new SelectList(db.Employee_Type, "Id",
        "EmployeeType", employee.EmployeeTypeID);
    return View(employee);
}

Step 8: Enhance the current Employee index view to add Medical Allowance and House Allowance columns.

Step 9: Run the application and notice that we have achieved the business requirement by using Factory Method pattern. Below illustrated diagram depicts how we have converted the simple to factory method implementation.

Factory Method Design Pattern example

Design Patterns tutorial for beginners

3 comments:

  1. On step 7: Below is the corrected code. The output of "empFactory.ApplySalary()" is not being assigned to employee object.

    ReplyDelete
    Replies
    1. Since classes are reference types, I think there is no need to return the employee object from ApplySalary method.
      Please correct me if I am wrong.

      Delete
  2. Missed the modification of PermanentEmployeeManager class GetHouseAllowance method in this code

    ReplyDelete

It would be great if you can help share these free resources