Как выбрать между одним большим методом с пассивными перегрузками и кучей небольших перегрузок, каждый из которых выполняет небольшой объем работы? - PullRequest
7 голосов
/ 25 сентября 2010

Существует два способа реализации перегрузок.Первый заключается в том, чтобы делать все в одном методе / конструкторе и вызывать его из других перегрузок, что приводит к более длинным телам методов .Второй - делать минимум при каждой перегрузке, таким образом, имея код, иногда трудный для навигации и понимать, какая перегрузка что делает.

Например, если две перегрузки класса Cat являются:

public Cat(string name, int? weight, Color mainColor);
public Cat(string name);

Есть два способа реализовать это:

Первый тип

public Cat(string name, int? weight, Color mainColor)
{
    // Initialize everything.
    this.name = name;
    if (weight.HasValue) this.weight = weight.Value;

    // There is a bug here (see the anwer of @Timwi): mainColor can be null.
    this.colors = new List<Colors>(new[] { mainColor });
}

public Cat(string name)
    : this(name, null, null)
{
    // Nothing else to do: everything is done in the overload.
}

Второй тип

public Cat(string name)
{
    // Initialize the minimum.
    this.name = name;
    this.colors = new List<Colors>();
}

public Cat(string name, int? weight, Color mainColor)
    : this(name)
{
    // Do the remaining work, not done in the overload.
    if (weight.HasValue) this.weight = weight.Value;
    this.colors.Add(mainColor);
}

Вопросы

  1. Как эти два типа перегрузок называются (чтобы искать дополнительную информацию в Интернете или в книгах)?
  2. Что должно быть основные проблемы / факторы, которые следует учитывать при выборе между этими типами?

Примечание: поскольку C # 4.0 позволяет вам указывать необязательные параметры, чтобы избежать двусмысленности, допустим, я говорюТолько C # 3.0.

Ответы [ 2 ]

3 голосов
/ 25 сентября 2010

Я думаю, что это еще один из тех примеров, когда ни один, догматический ответ не будет разумно охватывать все случаи. Я бы всегда смотрел на отдельный случай и принимал решение на основе всех доступных факторов.

Одним из факторов является то, что первый имеет много ifs.В вашем коде также есть ошибка: вы добавляете значение null в список цветов;чтобы исправить эту ошибку, вам нужно еще больше ifs.Такой конструктор может легко запутаться.Множество ifs указывает на то, что есть несколько случаев, в которых логика существенно отличается, поэтому наличие отдельных конструкторов для каждого из этих случаев имеет смысл.

Однако в случаях, когда не так много ifsлогика одинакова для всех, поэтому теперь имеет смысл вызывать один конструктор, который выполняет эту логику и делает это хорошо.Тогда есть только одно место для его обслуживания.

Другой фактор заключается в том, что в вашем примере первый оставляет weight неинициализированным. Это не должно быть плохо , потому что, к счастью, инициализация по умолчанию в C # предсказуема;но я бы счел это плохим тоном, если бы объявление поля для weight инициализировало его чем-то ненулевым, и только некоторые конструкторы перезаписывают это значение по умолчанию другим значением.Параметры конструктора и / или вызов this(...) лучше подходят для документирования значения по умолчанию для этого поля.(Предпочтительно параметры конструктора, потому что тогда даже клиентский программист может видеть значение по умолчанию , но очевидно, что для этого требуется C # 4.) Конечно, также возможно инициализировать все поляиспользуя инициализатор поля и оставьте конструктор (и) пустым, что является разумной стратегией, если у вас есть только один конструктор без аргументов.

Так что, как вы сказали, вы не хотите, чтобы тела методов получалислишком долго, но вы также не хотите, чтобы код становился слишком сложным для навигации, поэтому вам нужно найти баланс между ними для любой конкретной ситуации.

1 голос
/ 25 сентября 2010

Первый

Перегрузка конструктора всегда должна вызывать друг друга или общий метод инициализатора. Это вопрос рефакторинга и модульности кода, чтобы вам пришлось вносить изменения только один раз.

Например, если вы хотите добавить это:

this.name = name ?? string.Empty;

Во втором случае вы должны сделать это в двух местах для второго, но в одном месте в первом.

Также в соответствии с соглашением упорядочьте конструкторы так, чтобы они сначала начинались с наименьшего количества параметров.

...