We'll be creating an Abstract class since we need to calculate
- Rent allowance for the permanent employee
- Medical allowance for the contract employee
Sample Code Download: PatternsFactoryMethod.zip (Visual Studio 2017 Console App)
Basic Setup
Create Enum for the EmployeeType
public enum EmployeeType
{
Contract = 1,
Permanent = 2
}
Create Data Model Class
This model will represent a database table, which we'll populate without HourlyPay and Bonus since this will be specific to each employee type.
public class Data
{
public string Name { get; set; }
public string Department { get; set; }
public decimal? HourlyPay { get; set; }
public decimal? Bonus { get; set; }
public decimal? RentAllowance { get; set; }
public decimal? MedicalAllowance { get; set; }
public EmployeeType EmployeeType { get; set; }
}
Fill Employees and Display Employees
Since this is a console app, fill data and write to console
class Program
{
static void Main(string[] args)
{
var employees = FillEmployees();
PrintEmployees(employees);
Console.ReadLine();
}
private static List FillEmployees()
{
var employees = new List
{
new Data{Name = "Jason", Department = "IT", EmployeeType = EmployeeType.Contract },
new Data{Name = "Brian", Department = "IT", EmployeeType = EmployeeType.Permanent }
};
return employees;
}
private static string Tab()
{
return "\t";
}
private static void PrintEmployees(List employees)
{
//header
Console.ForegroundColor = ConsoleColor.DarkYellow;
var header = $"#{Tab()}Name{Tab()}Department{Tab()}Type{Tab()}{Tab()}HourlyPay{Tab()}Bonus{Tab()}Rent{Tab()}Medical";
Console.WriteLine(header);
Console.ResetColor();
//no data
if (employees == null || !employees.Any())
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("No Data");
Console.ResetColor();
return;
}
//print data
var row = 1;
foreach (var emp in employees)
{
var message = row + Tab() + emp.Name + Tab() + emp.Department + Tab()+Tab() + emp.EmployeeType+Tab();
message += emp.HourlyPay.HasValue
? emp.HourlyPay.GetValueOrDefault().ToString("N0") + Tab() + Tab()
: "" + Tab() + Tab();
message += emp.Bonus.HasValue
? emp.Bonus.GetValueOrDefault().ToString("N0") + Tab()
: "" + Tab() ;
message += emp.RentAllowance.HasValue
? emp.RentAllowance.GetValueOrDefault().ToString("N0") + Tab()
: "" + Tab() ;
message += emp.MedicalAllowance.HasValue
? emp.MedicalAllowance.GetValueOrDefault().ToString("N0")
: "";
Console.WriteLine(message);
row += 1;
}
}
Common Pieces Setup
We'll work with an interface for the common pieces. The interface will get applied to ContractEmployeeManager or PermanentEmployeeManager. It will have two methods which are common to both types of employees. RentAllowence and MedicalAllowence will not be part of the interface since these are specific to a specific employee and detailed towards the top.
IEmployeeManager Interface
public interface IEmployeeManager
{
decimal GetBonus();
decimal GetPay();
}
PermanentEmployeeManager
GetHouseAllowence is specific to permanent employee so is not part of the above interface.
public class PermanentEmployeeManager : IEmployeeManager
{
public decimal GetBonus()
{
return 30;
}
public decimal GetPay()
{
return 50;
}
public decimal GetHouseAllowance()
{
return 10;
}
}
ContractEmployeeManager
GetMedicalAllowance is specific to contract employee so is not part of the above interface.
public class ContractEmployeeManager : IEmployeeManager
{
public decimal GetBonus()
{
return 15;
}
public decimal GetPay()
{
return 80;
}
public decimal GetMedicalAllowance()
{
return 8;
}
}
Abstract and Factory Classes Setup
Since we have two very specific methods for both contract and permanent employees, we'll work with an abstract class and provide an abstract method to fill in these.
Abstract Class BaseEmployeeFactory
//BaseEmployeeFactory abstract class will be inherited by
//1. ContractEmployeeFactory => which in turn will use ContractEmployeeManager
//2. PermanentEmployeeFactory => which in turn will use PermanentEmployeeManager
public abstract class BaseEmployeeFactory
{
protected EmpData _empData;
public BaseEmployeeFactory(EmpData empData)
{
_empData = empData;
}
public EmpData ApplyBonusPay()
{
//Create abstract method will give us the appropriate contract or permanent employee object using the appropriate Factory class
//once we have the object then we'll get the bonus and hourly pay since these are in both the Manager classes
//Rent allowance and medical allowance will be handled separately
//Rent allowance for the permanent employee only
//Medical allowance for the contract employee
//the Create abstract method will fill the _empData
var empManager = this.Create();
_empData.Bonus = empManager.GetBonus();
_empData.HourlyPay = empManager.GetPay();
return _empData;
}
public abstract IEmployeeManager Create();
}
ContractEmployeeFactory Class
It will fill in the medical allowance and then will return the object to ContractEmployeeManager
public class ContractEmployeeFactory : BaseEmployeeFactory
{
public ContractEmployeeFactory(EmpData empData) : base(empData)
{
}
public override IEmployeeManager Create()
{
var manager = new ContractEmployeeManager();
//in base
_empData.MedicalAllowance = manager.GetMedicalAllowance();
return manager;
}
}
PermanentEmployeeFactory Class
It will fill in the rent allowance and then will return the object to PermanentEmployeeManager
public class PermanentEmployeeFactory : BaseEmployeeFactory
{
public PermanentEmployeeFactory(EmpData empData) : base(empData)
{
}
public override IEmployeeManager Create()
{
var manager = new PermanentEmployeeManager();
//in base
_empData.RentAllowance = manager.GetHouseAllowance();
return manager;
}
}
EmpFactory Class to Tie All Togther
EmpFactory class will be our factory class and will return the appropriate object depending upon the employee type.
public class EmpFactory
{
public BaseEmployeeFactory CreateFactory(EmpData empData)
{
BaseEmployeeFactory factory = null;
if (empData.EmployeeType == EmployeeType.Contract)
{
factory = new ContractEmployeeFactory(empData);
}
else if (empData.EmployeeType == EmployeeType.Permanent)
{
factory = new PermanentEmployeeFactory(empData);
}
return factory;
}
}
Filling the Pieces and Displaying Data
static void Main(string[] args)
{
var employees = FillEmployees();
foreach (var emp in employees)
{
//EmpFactory
var empFactory = new EmpFactory();
//returns object as BaseEmployeeFactory
var factory = empFactory.CreateFactory(emp);
//we have either object to ContractEmployeeFactory or PermanentEmployeeFactory
factory.ApplyBonusPay();
}
PrintEmployees(employees);
Console.ReadLine();
}