Пример оптимизации оператора switch при подстройке пользовательского интерфейса


Исходный код

private void OnRdbDatesCheckedChanged(object sender, EventArgs e)
{
    if (rdbMonth.Checked)
        MakeDateViewVisible("month");
    elseif (rdbQuarter.Checked)
        MakeDateViewVisible("quarter");
    elseif (rdbYear.Checked)
        MakeDateViewVisible("year");
    else
        MakeDateViewVisible("individual");
}

private void MakeDateViewVisible(string dateView)
{
    switch (dateView)
    {
        case "year":
            YearView.Visible = true;
            QuarterView.Visible = false;
            MonthView.Visible = false;
            IndividualDatesView.Visible = false;
            break;
        case "quarter":
            YearView.Visible = false;
            QuarterView.Visible = true;
            MonthView.Visible = false;
            IndividualDatesView.Visible = false;
            break;
        case "month":
            YearView.Visible = false;
            QuarterView.Visible = false;
            MonthView.Visible = true;
            IndividualDatesView.Visible = false;
            break;
        case "individual":
            YearView.Visible = false;
            QuarterView.Visible = false;
            MonthView.Visible = false;
            IndividualDatesView.Visible = true;
            break;
    }
}

Что так в исходном коде

Разделение ответственностей между методами OnRdbDatesCheckedChanged и MakeDateViewVisible просто идеально! Первый по сути выполняет функции контроллера, откликаясь на внешние воздействия. Второй подстраивает вид пользовательского интерфейса, не владея информацией об источнике команды: потребность изменить интерфейс может возникнуть не только как реакция на действия пользователя, но и как ответ на некие внутренние события, и просто в процессе инициализации.

Другими словами, первый метод обладает знанием о том, как реагировать на действия пользователя, второй — о том, как менять интерфейс в нужную сторону.

Что можно улучшить в исходном коде

Тем не менее, код второго метода выглядит громоздким.

Если внимательно посмотреть на каждую ветку оператора switch, то можно заметить простую закономерность: видимым становится только один элемент интерфейса из четырёх, причём какждый раз разный. Видимость меняется путём присвоения true или false полю Visible, причём true false являются результатом сравнения параметра dateView с одним из четырёх литералов. Причём каждый литерал соответствует своему элементу интерфейса.

Второй важный момент связан с магическими литералами. Непосредственно использовать в коде литералы строк или чисел возможно, но не принято из-за повышенных рисков снизить читаемость кода или повысить вероятность ошибок. Поэтому литералы принято прятать за константами; а серии констант оформляют в виде перечислений.

protected enum DateView {
    ViewYear,
    ViewQuarter,
    ViewMonth,
    ViewIndividual
}

private void MakeDateViewVisible(DateView dateView)
{
    YearView.Visible = dateView == ViewYear;
    QuarterView.Visible = dateView == ViewQuarter;
    MonthView.Visible = dateView == ViewMonth;
    IndividualDatesView.Visible = dateView == ViewIndividual;
}

Теория