Об этом не писал только ленивый…
Итак, почему
обобщённый репозиторий - это
антипаттерн.
Прежде всего, давайте вспомним, что из себя представляет паттерн репозиторий, особенно популярный в DDD.
Согласно Дяде Бобу, репозиторий посредничает между доменом и слоем представления данных, находясь в роли in-memory коллекции доменных объектов.
Проще говоря, это фасад для доступа к данным, который оборачивает конкретный источник данных: ORM, сервис, СУБД, файловая система, Active Directory и т.д.
Так вот, начну с неочевидного.
Если вы используете ORM, например, Entity Framework или NHibernate, то следует помнить, что эти библиотеки сами по себе предоставляют реализации не только обобщённых репозиториев, но и единиц работы Unit Of Work.
В случае EF
DbContext является UOW, а
DbSet<T> это обобщённый репозиторий.
В случае NHibernate оба паттерна инкапсулированы внутри
ISession.
Соответственно, создание новой обёртки поверх существующей аналогично переизобретению колеса, которое ещё и будет квадратным.
В отрыве от ORM, конечно обобщённые репозитории, в силу своей "обобщённости", превращаются в DAL код, намертво впаенный в алгоритмы бизнес-логики.
В результате, когда запросы будут устаревать, окажется, что по всему проекту разбросана неактуальная и сложная логика запросов, которую трудно поддерживать.
Также, репозиторий - это абстракция, которая больше нужна для работы с доменом, нежели с данными, и, соответственно, является его частью.
А домен не является обобщённым. Не каждая сущность может быть добавлена/удалена или отредактирована единым образом, не у каждой сущности будет репозиторий вовсе.
Запросы
кардинальным образом различаются, вследствие этого API конкретного репозитория становится уникальным, согласно соответствующей сущности.
С другой стороны, репозиторий определяет операции, которые хранилище данных можнт осуществлять над доменными объектами.
А обобщённый вариант не предоставляет осмысленного контракта.
Просто сравните две сигнатуры ниже:
// вообще не понятно, что происходит
IEnumerable<T> Find(object param);
// более читабельный код, который чётко определяет
// отношение между хранилищем данных и доменным объектом
IEnumerable<Customer> FindCustomerByName(string name);
Все эти аргументы говорят в пользу того, что создание обобщённых репозиториев -
плохо в любом году.
#полезное #tips