简体   繁体   English

避免 if/else 的最佳实现

[英]Best Implementation to avoid if/else

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 :我将Enum用于假期, main我想根据用户的选择进行注册,如下所示:

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我想知道实现此解决方案的更好方法,或者只是更改将数据插入抽象列表的代码

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
}

You have the same(almost) implementation for HolidayValidation and you dont use typeOfHoliday .您对HolidayValidation具有相同(几乎)的实现,并且不使用typeOfHoliday

From what you have posted you might as well add the Holiday enum as parameter and property to base class( Abstract ) and not have any inheritance at all.根据您发布的内容,您不妨将 Holiday 枚举作为参数和属性添加到基类( Abstract ),而根本没有任何继承。 Implement the HolidayValidation in the base class and use the Holiday property to compare to Days在基类中实现HolidayValidation并使用 Holiday 属性与Days进行比较

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 :Main我变成了这个:

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对于typeOfHoliday,我使用了Holiday类型,因此使用起来更容易,并且用户做出的选择我将其转换为Enum Holiday

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM