Уровень доступа к данным: список экспонирования: плохая идея?


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

Я собираюсь внутренне реализовать данные в виде списка, но я помню, что читал что-то о том, чтобы не предоставлять тип списка потребителям, если он не нужен.

public List<User> GetAllUsers() // non C# users: that means List of User :)

Знаете, почему (google не помог)? Что вы обычно выставляете за такие вещи? Илист? Интерфейс IEnumerable?

3 3

3 ответа:

Обычно лучше всего выставлять наименее мощный интерфейс, с которым пользователь все еще может осмысленно работать. Если пользователю просто нужны некоторые перечислимые данные, верните IEnumerable<User>. Если этого недостаточно, потому что пользователь должен иметь возможность изменять список (внимание! не должно часто быть так), верните IList<User>.

/ EDIT:

В своем комментарии Джоэл задает вполне обоснованный вопрос: почему, в самом деле, выставлять наименее мощный интерфейс вместо того, чтобы предоставить пользователю максимальную мощность? (перефразировано)

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

Что еще более важно, это раскрывает части внутренней реализации через возвращаемый тип. Если мне нужно изменить реализацию в будущем, чтобы он больше не использовал контейнер IList, у меня есть проблема: мне нужно либо изменить контракт метода, введя изменение, нарушающее сборку. Или мне нужно скопировать данные в контейнер списка.

В качестве примера представим, что эффективная реализация использует словарь и просто возвращает коллекцию Values, которая не реализует IList.

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

Вы должны тщательно подумать, прежде чем возвращать IEnumerable. Если базовый код использует" yield " для генерации IEnumerable, или использует LINQ, то вы в конечном итоге будете держать открытыми любые используемые ресурсы.

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

С другой стороны, возврат IList подразумевает, что вызывающий объект может изменить возвращаемый объект. список.