Factory Method Design Pattern
Factory Pattern or Factory Method Pattern is a creational design pattern that provides an interface or abstract class for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. In other words, subclasses are responsible to create the instance of the class.
Contents
Business Requirement Example
- We need two types of employee permanent and contract.
- Contract employee's Salary is 80000 and Bonus is 1000.
- Permanent employee's Salary is 50000 and Bonus is 5000.
- Contract employee has medical allowance of 2000. Only for Contract employee.
- Permanent employee has house allowance of 5000. Only for Permanent employee.
Code Example
public interface IEmployee { void setSalary(); void setBonus(); } class PermanentEmployee : IEmployee { public string Name { get; set; } public EmployeeTypes EmployeeType { get; set; } public int Salary { get; set; } public int Bonus { get; set; } public void setBonus() { Bonus = 5000; } public void setSalary() { Salary = 50000; } public void setHouseAllowance() { Salary += 5000; } } class ContractEmployee : IEmployee { public string Name { get; set; } public EmployeeTypes EmployeeType { get; set; } public int Salary { get; set; } public int Bonus { get; set; } public void setBonus() { Bonus = 1000; } public void setSalary() { Salary = 80000; } public void setMedicalAllowance() { Salary += 2000; } } class EmployeeFactory { public IEmployee GetEmployee(string name, EmployeeTypes employeeType) { IEmployee _employee= null; if (employeeType.Id == 1) { _employee = new PermanentEmployee() { Name = name }; } else if (employeeType.Id == 2) { _employee = new ContractEmployee() { Name = name }; } return _employee; } } class EmployeeTypes { public int Id { get; set; } public string Name { get; set; } } class Program { static void Main(string[] args) { EmployeeTypes _contractEmplyeeType = new EmployeeTypes { Id = 2, Name = "Contract Emplyee" }; EmployeeTypes _permanentEmplyeeType = new EmployeeTypes { Id = 1, Name = "Permanent Emplyee" }; EmployeeFactory employeeFactory = new EmployeeFactory(); IEmployee _contractEmplyee = employeeFactory.GetEmployee("Jhon" , _contractEmplyeeType); _contractEmplyee.setBonus(); _contractEmplyee.setSalary(); IEmployee _permanentEmplyee = employeeFactory.GetEmployee("Mario", _permanentEmplyeeType); _permanentEmplyee.setBonus(); _permanentEmplyee.setSalary(); } }
Problem
If we need to compute the house allowance specific to Permanent employee and medical allowance specific to Contract employee then Simple Factory Pattern will be difficult as we can not call setHouseAllowance() or setMedicalAllowance() function on the Main() function and our EmployeeFactory class have to take-care of the computation based on the instance of the object.
This approach violates the SOLID Principles.
Solution
We have to created PermanentEmployeeFactory and ContractEmployeeFactory which will calculate the house allowance specific to Permanent employee and medical allowance specific to Contract employee. And the common function setBonus() and setSalary() will be executed by BaseEmployeeFactory class.
In EmployeeFactory we will call ApplySalary() function, which will create an instance of my object and do all the calculation.
Code Example
class Employee { public string Name { get; set; } public EmployeeTypes EmployeeType { get; set; } public int Salary { get; set; } public int Bonus { get; set; } public int HouseAllowance { get; set; } public int MedicalAllowance { get; set; } } public interface IEmployee { void setSalary(); void setBonus(); } class PermanentEmployee : IEmployee { Employee employee = new Employee(); public void setBonus() { employee.Bonus = 5000; } public void setSalary() { employee.Salary = 50000; } public void setHouseAllowance() { employee.HouseAllowance = 5000; } } class ContractEmployee : IEmployee { Employee employee = new Employee(); public void setBonus() { employee.Bonus = 1000; } public void setSalary() { employee.Salary = 80000; } public void setMedicalAllowance() { employee.MedicalAllowance = 2000; } } abstract class BaseEmployeeFactory { public IEmployee ApplySalary() { IEmployee emp = this.Create(); emp.setBonus(); emp.setSalary(); return emp; } public abstract IEmployee Create(); } class PermanentEmployeeFactory : BaseEmployeeFactory { public override IEmployee Create() { PermanentEmployee permanentEmployee = new PermanentEmployee(); permanentEmployee.setHouseAllowance(); return permanentEmployee; } } class ContractEmployeeFactory : BaseEmployeeFactory { public override IEmployee Create() { ContractEmployee contractEmployee = new ContractEmployee(); contractEmployee.setMedicalAllowance(); return contractEmployee; } } class EmployeeFactory { public IEmployee GetEmployee(string name, EmployeeTypes employeeType) { BaseEmployeeFactory _employeeFactory = null; if (employeeType.Id == 1) { _employeeFactory = new PermanentEmployeeFactory(); } else if (employeeType.Id == 2) { _employeeFactory = new ContractEmployeeFactory(); } return _employeeFactory.ApplySalary(); //return _employeeFactory; } } class EmployeeTypes { public int Id { get; set; } public string Name { get; set; } } class Program { static void Main(string[] args) { var obj = FactoryMethodDesignPattern(); } static List<IEmployee> FactoryMethodDesignPattern() { EmployeeTypes _contractEmplyeeType = new EmployeeTypes { Id = 2, Name = "Contract Emplyee" }; EmployeeTypes _permanentEmplyeeType = new EmployeeTypes { Id = 1, Name = "Permanent Emplyee" }; EmployeeFactory employeeFactory = new EmployeeFactory(); IEmployee _contractEmplyee = employeeFactory.GetEmployee("Jhon", _contractEmplyeeType); IEmployee _permanentEmplyee = employeeFactory.GetEmployee("Mario", _permanentEmplyeeType); List<IEmployee> listObj = new List<IEmployee>(); listObj.Add(_contractEmplyee); listObj.Add(_permanentEmplyee); return listObj; } }
Advantage of Factory Method Design Pattern
- Allows you to hide implementation of an application seam (the core interfaces that make up your application)
- Allows you to easily test the seam of an application (that is to mock/stub) certain parts of your application so you can build and test the other parts
- Allows you to change the design of your application more readily, this is known as loose coupling.