Лучше использовать List или Collection? - PullRequest
36 голосов
/ 27 мая 2010

У меня есть объект, который хранит некоторые данные в списке. Реализация может измениться позже, и я не хочу предоставлять внутреннюю реализацию конечному пользователю. Однако пользователь должен иметь возможность изменять и получать доступ к этой коллекции данных. В настоящее время у меня есть что-то вроде этого:

public List<SomeDataType> getData() {
   return this.data;
}

public void setData(List<SomeDataType> data) {
   this.data = data;
}

Значит ли это, что я допустил утечку внутренних деталей реализации? Должен ли я делать это вместо этого?

public Collection<SomeDataType> getData() {
   return this.data;
}

public void setData(Collection<SomeDataType> data) {
   this.data = new ArrayList<SomeDataType>(data);
}

Ответы [ 8 ]

25 голосов
/ 27 мая 2010

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

17 голосов
/ 01 июля 2010

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

Возврат коллекции приведет к неоднозначности для пользователя, поскольку возвращаемая коллекция может быть либо: Set, List или Queue.

9 голосов
/ 05 июня 2010

Независимо от возможности индексирования в списке с помощью List.get (int), ожидают ли пользователи (или вы), что элементы коллекции находятся в надежном и предсказуемом порядке? Может ли коллекция содержать несколько одинаковых предметов? Оба они являются ожиданиями списков, которые не являются общими для более общих коллекций. Это тесты, которые я использую при определении того, какую абстракцию выставлять конечному пользователю.

8 голосов
/ 27 мая 2010

При возврате реализации интерфейса или класса, который находится в высокой иерархии, практическое правило заключается в том, что объявленный тип возврата должен быть наивысшим уровнем, обеспечивающим минимальную функциональность, которую вы готовы гарантировать вызывающей стороне, и что звонящий разумно нуждается. Например, предположим, что вы действительно возвращаете ArrayList. ArrayList реализует List и Collection (среди прочего). Если вы ожидаете, что вызывающая сторона должна использовать функцию get (int x), то она не сработает для возврата Collection, вам нужно будет вернуть List или ArrayList. Пока вы не видите причин, по которым вы когда-либо изменили бы свою реализацию на использование чего-то другого, кроме списка - скажем, набора - тогда правильный ответ - вернуть список. Я не уверен, есть ли в ArrayList какая-либо функция, которой нет в List, но если она есть, применимы те же аргументы. С другой стороны, когда вы возвращаете Список вместо Коллекции, вы в какой-то степени заблокировали свою реализацию. Чем меньше вы вкладываете в свой API, тем меньше вы ограничиваете будущие улучшения.

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

5 голосов
/ 27 мая 2010

Использование наиболее общего типа, а именно Collection, имеет смысл, если только нет явной причины использовать более конкретный тип - List. Но что бы вы ни делали, если это API для общественного потребления, в документации должно быть ясно, что он делает; если он возвращает мелкую копию коллекции, так и скажите.

1 голос
/ 27 мая 2010

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

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

0 голосов
/ 27 мая 2010

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

0 голосов
/ 27 мая 2010

Если бы меня беспокоило скрытие внутреннего представления моих данных внешним пользователем, я бы использовал XML или JSON. В любом случае, они довольно универсальны.

...