Разбиение публичных функций-членов на множество приватных функций-членов - PullRequest
3 голосов
/ 17 декабря 2009

Когда я пишу открытую функцию-член класса, которая делает несколько вещей, например ..

void Level::RunLogic(...);

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

void Level::RunLogic(...) {
 DoFirstThing();
 DoSecondThing();
 DoThirdThing();
}

С функциями DoThing, являющимися частными функциями-членами. В Code Complete Стив МакКоннел рекомендует сократить количество функций в классе, но я бы предпочел не просто помещать весь этот код в одну функцию. Мое предположение о его истинном значении состоит в том, что у класса не должно быть слишком много функциональности, но мне просто интересно, что другие программисты думают по этому поводу.

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

Ответы [ 7 ]

2 голосов
/ 17 декабря 2009

Вы правы в том, что хотите сохранить публичный метод простым и разделить его функциональность на несколько приватных методов.

Макконнелл прав, что вам следует сократить количество методов, которые вы храните в классе.

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

Лучший способ добиться этого, конечно, будет зависеть от деталей вашего кода.

1 голос
/ 17 декабря 2009

Я согласен с разделением функциональности.

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

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

1 голос
/ 17 декабря 2009

Я рекомендую разбить их на отдельные методы, где каждый метод выполняет одну небольшую задачу и имеет описание для каждого частного метода. Разбиение методов и имен методов сделало бы логический код более читабельным! Для сравнения:

double average(double[] numbers) {
  double sum = 0;
  for (double n : numbers) {
    sum += n;
  }
  return sum / numbers.length;
}

до:

double sum(double[] numbers) {
  double sum = 0;
  for (double n : numbers) sum += n;
  return sum;
}

double average(double[] numbers) {
    return sum(numbers) / numbers.length;
}

Code Complete обращается к интерфейсу, который предоставляет каждый класс, а не к реализации.

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

0 голосов
/ 19 января 2010

Эмпирическое правило, которое я использую, заключается в том, что ни одна функция не будет занимать больше, чем полный экран за раз. Хотя это довольно просто, но полезно, когда вы можете «взять все это» по одному экрану за раз. Это также ограничит (по определению) сложность любого одного метода. Когда от вас ожидают, что вы передадите свою работу коллеге для дальнейшего технического обслуживания, обновлений и исправления ошибок (!), Поддерживать простоту - хорошо. Имея это в виду, я согласен с тем, что простота ваших публичных методов - почти всегда правильный выбор.

0 голосов
/ 17 декабря 2009

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

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

0 голосов
/ 17 декабря 2009

Вы непреднамеренно соблюдаете правила ff:

A class should have only one reason to change / Single responsibility principle

Что хорошо. Правильно распределяя обязанности, вы гарантируете, что ваше приложение не сломается из-за change

0 голосов
/ 17 декабря 2009

Одно правило, которое я использую, - это правило трех. Если я делаю одну и ту же вещь три раза в разных местах, то стоит иметь отдельную (возможно частную) функцию-член, которая инкапсулирует это общее поведение.

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

Относительно кода Полный комментарий о количестве функций в классе, помните, что наибольший риск, связанный с количеством функций, связан, прежде всего, со сложностью внешнего интерфейса. Чем больше точек входа вы предоставляете другим людям для работы, тем больше вероятность того, что что-то пойдет не так (например, из-за ошибки в одном из открытых участников, неправильного ввода и т. Д.). Добавление закрытой функции-члена не увеличивает сложность общедоступного API.

...