Difference between revisions of "Factory Method Design Pattern"

From JholJhapata
 
Line 6: Line 6:
 
* Permanent employee's Salary is 50000 and Bonus is 5000.
 
* Permanent employee's Salary is 50000 and Bonus is 5000.
 
* Contract employee has medical allowance of 2000. '''Only for Contract employee'''.
 
* Contract employee has medical allowance of 2000. '''Only for Contract employee'''.
* Permanent employee has hose allowance of 5000. '''Only for Permanent employee'''.
+
* Permanent employee has house allowance of 5000. '''Only for Permanent employee'''.
 
=== Code Example ===
 
=== Code Example ===
 
     public interface IEmployee
 
     public interface IEmployee
Line 27: Line 27:
 
             Salary = 50000;
 
             Salary = 50000;
 
         }
 
         }
         public void setHoseAllowance()
+
         public void setHouseAllowance()
 
         {
 
         {
 
             Salary += 5000;
 
             Salary += 5000;
Line 84: Line 84:
 
             EmployeeTypes _contractEmplyeeType = new EmployeeTypes
 
             EmployeeTypes _contractEmplyeeType = new EmployeeTypes
 
             {
 
             {
                 Id = 1,
+
                 Id = 2,
 
                 Name = "Contract Emplyee"
 
                 Name = "Contract Emplyee"
 
             };
 
             };
Line 102: Line 102:
 
     }
 
     }
 
== Problem ==
 
== Problem ==
If we need to compute the hose allowance specific to Permanent employee and medical allowance specific to Contract employee then [[Simple Factory Pattern]] will be difficult as we can not call setHoseAllowance() 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.  
+
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]].
 
This approach violates the [[SOLID Principles]].
  
 
== Solution ==
 
== 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 ===
 
=== 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 ==
 
== 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.

Latest revision as of 13:52, 23 February 2020

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.

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.