Вернуть конкретные или абстрактные типы данных? - PullRequest
4 голосов
/ 25 мая 2009

Я нахожусь в процессе чтения Code Complete, и ближе к концу книги, в главе о рефакторинге, автор перечисляет несколько вещей, которые вы должны сделать, чтобы улучшить качество вашего кода при рефакторинге.

Одним из его пунктов было то, что всегда возвращает как можно более конкретные типы данных , особенно при возврате коллекций, итераторов и т. Д. Итак, как я понял, вместо возврата, скажем, Collection<String>, вы должны вернуть HashSet<String>, если вы используете этот тип данных внутри метода.

Это смущает меня, потому что звучит так, будто он призывает людей нарушить правило сокрытия информации. Теперь я понимаю это, когда говорю о методах доступа, это очевидный случай. Но когда при расчете и распределении данных, а уровень абстракции метода не подразумевает прямой структуры данных, я считаю, что лучше всего возвращать как можно более абстрактный тип данных , пока данные не падают. кроме (я бы не возвратил Object вместо Iterable<String>, например).

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

Ответы [ 6 ]

3 голосов
/ 25 мая 2009

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

По моему мнению, вы всегда должны возвращать List, а не LinkedList или ArrayList, потому что разница скорее в деталях реализации, а не в семантике. Ребята из API коллекций Google для Java делают еще один шаг вперед: они возвращаются (и ожидают) итераторов, где этого достаточно. Но они также рекомендуют по возможности возвращать ImmutableList, -Set, -Map и т. Д., Чтобы показать вызывающему абоненту, что ему не нужно делать защитную копию.

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

1 голос
/ 25 мая 2009

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

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

@ Gishu

Если ваш API требует, чтобы клиенты отбрасывали его большую часть времени, ваш дизайн забит. Зачем возвращать X, если клиенты должны привести к Y.

1 голос
/ 25 мая 2009

Не могу найти никаких доказательств, подтверждающих мою претензию, но идея / руководство выглядит так:

Будьте максимально снисходительны при принятии ввода . Выберите обобщенный тип над специализированным типом. Это означает, что клиенты могут использовать ваш метод с различными специализированными типами. Таким образом, IEnumerable или IList в качестве входного параметра будут означать, что метод может запускаться из ArrayList или ListItemCollection. Это увеличивает вероятность того, что ваш метод полезен.

Будьте максимально строги при возврате значений . Предпочитаю специализированный тип, если это возможно. Это означает, что клиентам не нужно перебирать или перебирать циклы для обработки возвращаемого значения. Также специализированные типы имеют большую функциональность. Если вы решите вернуть IList или IEnumerable, количество действий, которые может сделать вызывающий объект, с вашим возвращаемым значением, значительно сокращается, например, Если вы возвращаете IList через ArrayList, чтобы получить количество возвращаемых элементов - используйте свойство Count, клиент должен выполнить downcast. Но тогда такой унылости побеждает цель - работает сегодня .. не будет завтра (если вы измените Тип возвращаемого объекта). Таким образом, для всех целей клиент не может легко получить количество элементов - что приводит его к написанию обычного стандартного кода (в нескольких местах или в качестве вспомогательного метода)

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

0 голосов
/ 25 мая 2009

Определенный тип возвращаемого значения гораздо более ценный, поскольку он:

  1. уменьшает возможные проблемы с производительностью при обнаружении функциональности с помощью приведения или отражения
  2. повышает читаемость кода
  3. на самом деле НЕ выставляет больше, чем необходимо.

Тип возврата функции специально выбран для обслуживания ВСЕХ ее вызывающих. Именно вызывающая функция должна ИСПОЛЬЗОВАТЬ возвращаемую переменную настолько абстрактно, насколько это возможно, поскольку вызывающая функция знает, как будут использоваться данные.

Нужно ли только пересекать структуру? нужно ли сортировать структуру? преобразовать это? клонировать это? Это вопросы, на которые может ответить только вызывающий объект, и, следовательно, может использовать абстрактный тип. Вызванная функция ДОЛЖНА обеспечивать все эти случаи.

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

0 голосов
/ 25 мая 2009

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

Кроме того, я бы понял это так:

Возврат как можно более абстрактного типа данных = возврат как можно более конкретного типа данных

т.е. когда ваш метод должен возвращать любой тип данных коллекции, возвращайте коллекцию, а не объект.

скажи мне, если я не прав.

0 голосов
/ 25 мая 2009

Я мог видеть, как в некоторых случаях может быть полезным возвращение более конкретного типа данных. Например, зная, что возвращаемое значение является LinkedList, а не просто List, вы сможете удалить из списка, зная, что это будет эффективно.

...