Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Implementation to avoid if/else

Tags:

c#

oop

I am doing a program for vacation in a company and the time that is allowed to be in a specific holiday.

I used an Abstract class with an abstract method :

public abstract class Abstract : TimeLength
{
    public AbstractTest(string employeeCode, string employee, string typeOfHoliday, DateTime startDate, DateTime endDate) : base(startDate, endDate, "")
    {
        TypeOfHoliday = typeOfHoliday;
        Employee = employee;
        EmployeeCode = employeeCode;
    }
    public string EmployeeCode { get; set; }
    public string Employee { get; set; }
    public string TypeOfHoliday { get; set; }

    public abstract bool HolidayValidation(string typeOfHoliday);
}

And I used multiple class that inherent from this abstract class like this two :

class MarriageVacation : Abstract
{
    public MarriageVacation(string employeeCode, string employee, string typeOfHoliday, DateTime startDate, DateTime endDate) : base(employeeCode, employee, typeOfHoliday, startDate, endDate)
    {
    }

    public override bool HolidayValidation(string typeOfHoliday)
    {
        if (Days() > (int)Holiday.MarriageVacation)
        {
            MessageBox.Show("Marriage Vacation Can only be 5 Days");
            return false;
        }
        else
            return true;
    }
}


class Bereavement : Abstract
{
    public Bereavement(string employeeCode, string employee, string typeOfHoliday, DateTime startDate, DateTime endDate) : base(employeeCode, employee, typeOfHoliday, startDate, endDate)
    {
    }

    public override bool HolidayValidation(string typeOfHoliday)
    {
        if (Days() > (int)Holiday.Bereavement)
        {
            MessageBox.Show("Bereavement Can only be 5 Days");
            return false;
        }
        else
            return true;
    }
}

I use Enum for holidays and in the main I want to register this based on the users choice like this :

List<Abstract> holiday = new List<Abstract>();
if(CmbTypeHolidays.Text == Holiday.Bereavement.ToString())
        {
            var holid = new Bereavement(CmbEmpHolidays.Text.Split('-')[0], CmbEmpHolidays.Text.Split('-')[1], CmbTypeHolidays.Text, Convert.ToDateTime(StartDateHolidays.Value), Convert.ToDateTime(EndDateHolidays.Value));

            if (holid.HolidayValidation(CmbTypeHolidays.Text))
            {
                holiday.Add(holid);
                var bindingList = new BindingList<Abstract>(holiday);
                dataGridHolidays.DataSource = bindingList;
                controlPanelHolidays.Visible = false;
            }
        }
        else if (CmbTypeHolidays.Text == Holiday.MarriageVacation.ToString())
        {
            var holid = new MarriageVacation(CmbEmpHolidays.Text.Split('-')[0], CmbEmpHolidays.Text.Split('-')[1], CmbTypeHolidays.Text, Convert.ToDateTime(StartDateHolidays.Value), Convert.ToDateTime(EndDateHolidays.Value));

            if (holid.HolidayValidation(CmbTypeHolidays.Text))
            {
                holiday.Add(holid);
                var bindingList = new BindingList<Abstract>(holiday);
                dataGridHolidays.DataSource = bindingList;
                controlPanelHolidays.Visible = false;
            }
        }

I wanted to know a better way to implement this solution or just to change the code that inserts data to the abstract List

like image 441
enis Avatar asked Sep 18 '26 20:09

enis


2 Answers

You will need to set up a factory that maps holiday type name to the class implementing it:

private class HolidayConstructorArgs {
    public string EmployeeCode {get;set;}
    public string Employee {get;set;}
    public string TypeOfHoliday {get;set;}
    public DateTime From {get;set;}
    public DateTime To {get;set;}
}

private static readonly IDictionary<string,Func<HolidayConstructorArgs,AbstractHoliday>> HolidayByTypeCode =
    new Dictionary<string,Func<HolidayConstructorArgs,AbstractHoliday>> {
        [$"{Holiday.Bereavement}"] = a => new Bereavement(a.EmployeeCode, a.Employee, a.TypeOfHoliday, a.From, a.To)
    ,   [$"{Holiday.MarriageVacation}"] = a => new MarriageVacation(a.EmployeeCode, a.Employee, a.TypeOfHoliday, a.From, a.To)
    };

Now you can get the factory from the dictionary, and use it to instantiate the object:

if (HolidayByTypeCode.TryGetValue(CmbTypeHolidays.Text, out var factory)) {
    // This is where the "magic" happens:
    // Func<> will invoke the appropriate constructor without a conditional
    var holid = factory(
        new HolidayConstructorArgs {
            EmployeeCode = CmbEmpHolidays.Text.Split('-')[0]
        ,   Employee = CmbEmpHolidays.Text.Split('-')[1]
        ,   TypeOfHoliday = CmbTypeHolidays.Text
        ,   From = Convert.ToDateTime(StartDateHolidays.Value)
        ,   To = Convert.ToDateTime(EndDateHolidays.Value)
        }
    );
    // ... The rest of your code remains the same
}
like image 144
Sergey Kalinichenko Avatar answered Sep 21 '26 08:09

Sergey Kalinichenko


I made this changes based on the answers on this questions this is the Main class (Abstract) :

public class AbstractTest : TimeLength
{
    public AbstractTest(string employeeCode, string employee, Holiday typeOfHoliday, DateTime startDate, DateTime endDate) : base(startDate, endDate, "")
    {
        TypeOfHoliday = typeOfHoliday;
        Employee = employee;
        EmployeeCode = employeeCode;
    }
    public string EmployeeCode { get; set; }
    public string Employee { get; set; }
    public Holiday TypeOfHoliday { get; set; }

    public bool HolidayValidation(Holiday typeOfHoliday)
    {
        return Days() > (int)typeOfHoliday;
    }
}

And in the Main i changed into this :

Holiday MyStatus = (Holiday)Enum.Parse(typeof(Holiday), CmbTypeHolidays.Text, true);
        var holid = new AbstractTest(CmbEmpHolidays.Text.Split('-')[0], CmbEmpHolidays.Text.Split('-')[1], MyStatus, Convert.ToDateTime(StartDateHolidays.Value), Convert.ToDateTime(EndDateHolidays.Value));

        if (!holid.HolidayValidation(MyStatus))
        {
            holiday.Add(holid);
            var bindingList = new BindingList<AbstractTest>(holiday);
            dataGridHolidays.DataSource = bindingList;
            controlPanelHolidays.Visible = false;
        }
        else
        {
            MessageBox.Show($"{holid.TypeOfHoliday} Cant be more than {(int)MyStatus} Days");
        }

For the typeOfHoliday i used Holiday type so it is easier to work with and the choice that the user makes i convert it to Enum Holiday

like image 30
enis Avatar answered Sep 21 '26 09:09

enis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!