Подтвердить что ты не робот

Реализация хранилища

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

interface IProductRepository
{
    IQueryable<Product> FindAll();
}

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

В другом примере, который я нахожу много, ставьте все методы поиска в репозиторий

interface IProductRepository
{
    IEnumerable<Product> GetProductsInCategory(int categoryId);
    IEnumerable<Product> GetProductsStartingWith(string letter);
    IEnumerable<PromoCode> GetProductPromoCodes(int productId);
}

Какой путь вы рекомендуете взять? Или каковы преимущества/недостатки друг от друга?

Из моего понимания, прочитав http://martinfowler.com/eaaCatalog/repository.html, первый подход, похоже, лучше всего отражает это?

4b9b3361

Ответ 1

Первый ужасен. IQueryable похож на объект GOD. Очень сложно найти 100% полную реализацию (даже среди всех OR/M). Вы можете разоблачить свой ORM напрямую, а не использовать его, так как вы, вероятно, получите уровень утечки аберрации.

Джоэл говорит, что это лучше всего (текст из статьи wikipedia):

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

Запись блога Джоэлса

Второй подход намного проще реализовать и сохранить целостность абстракции.

Обновление

Ваш репозиторий нарушает принцип единой ответственности, поскольку он имеет две причины для изменения. Во-первых, если API-интерфейс продуктов изменен, а другой - если API-интерфейс PromoCode изменен. Вы должны imho использовать два разных репозитория, таких как:

interface IProductRepository
{
    IEnumerable<Product> FindForCategory(int categoryId);
    IEnumerable<Product> FindAllStartingWith(string letter);
}

interface IPromoCodeRepository
{
    IEnumerable<PromoCode> FindForProduct(int productId);
}

Измененные вещи:

  • Я обычно начинаю методы с Find, когда возвращаются несколько элементов и Get, если возвращается один элемент.
  • Более короткие имена методов = легче читать.
  • Единая ответственность. Легче сказать, какие классы, которые используют репозитории, имеют зависимости.

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

Ответ 2

Консенсус строит: 2-й вариант полностью. Помимо логики запросов, протекающей повсюду с помощью IQueryable, трудности с ее реализацией правильны, очень сложно тестировать и издеваться.

Ответ 3

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

Ответ 4

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

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

interface IRepository<T>
{
    IQueryable<T> FindAll();
}

interface IProductRepository : IRepository<Product>
{
    IEnumerable<Product> GetProductsInCategory(int categoryId);
    IEnumerable<Product> GetProductsStartingWith(string letter);
    IEnumerable<PromoCode> GetProductPromoCodes(int productId);
}

Рассмотрим также модульное тестирование. Конкретные методы намного проще высмеивать, чем IQueryable.

Ответ 5

Я действительно думаю, что 1-й лучше. Я принимаю решение о следующих факторах:

  • Если структура продукта получит рефакторинг:

    • IQueryable - вам нужно только изменить методы вызова в коде.
    • IEnumerables - вам нужно также изменить имена методов.

  • Если многие собираются вывести интерфейсы, которые вы хотите итератировать полиморфным способом:

    • IQueryable подход - преимущество универсальных имен унифицированных методов
    • IEnumerables - некоторые имена могут не описывать необходимый вам метод.

  • Elasticness

    • IQueryable подход - легко разделить на IEnumerables подход.
    • Подход IEnumerables - трудно конвертировать обратно в подход IQueryable.

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