Интерфейс (ы) репозитория в доменно-управляемом дизайне - PullRequest
1 голос
/ 31 мая 2011

Что касается договора между доменом и хранилищем, я полагаю, что лучше избегать всеобъемлющего универсального интерфейса IRepository с такими методами, как Create () и Delete ()? Если, конечно, естественно, что эти методы доступны для всех сущностей, с которыми я работаю. То, что я представляю, является редким сценарием.

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

Или лучше пойти по пути нескольких специализированных интерфейсов, таких как ICreatable, IDeletable, IRetrievable и т. Д .?

Ответы [ 4 ]

2 голосов
/ 02 июня 2011

Универсальные интерфейсы бесполезны, особенно в DDD, потому что они скрывают явно явные понятия. Представьте себе ваш обработчик команд / конструктор службы приложений:

public SomeCommandHandler(IRepository customerRepository, IRepository userRepository)

и сравните с этим:

public SomeCommandHandler(ICustomerRepository customerRepository, IUserRepository userRepository)

Последний вариант гораздо более явный, а ясность - это то, что вы ищете, выполняя DDD. Более того, если в ваших репозиториях используются все те же методы, вы, вероятно, создаете слой доступа к данным CRUD, который обычно не очень подходит для DDD.

2 голосов
/ 31 мая 2011

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

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

0 голосов
/ 01 июня 2011

Я полностью согласен с Gengzu. Я использовал этот подход в нескольких проектах, и в качестве архитектора решений я хочу, чтобы все разработчики в команде писали только необходимый и конкретный код. По моему опыту, в большинстве случаев вам нужен метод удаления и поиска и т. Д. В тех случаях, когда вы не хотите, это не должно диктоваться. Последствия этого будут заключаться в том, что репозитории, которые нуждаются в удалении, должны будут реализовать это, и это будет избыточный код. Все эти методы Delete могли бы быть реализованы с помощью абстрактного класса GenericRepository. Этот класс может работать против NHibernate и принимать общую сущность как T. Когда вы затем захотите создать, например, UserRepository, он будет наследоваться от GenericRepository и IUserRepository. Где IUserRepository наследуется от IRepository. Я добавлю код:

    public class UserRepository : GenericNHibernateRepository<User, int>, IUserRepository
        {
            #region IUserRepository Members


            public User GetUserByEmail(string email)
            {
                ICriterion[] query = {Restrictions.Eq("Email", email)};

                var list = GetByCriteria(query);

                if (list.Count == 0)

                    return null;
                else
                    return list[0];
            }

            #endregion
        }


    public interface IUserRepository : IRepository<User, int>
        {
            User GetUserByEmail(string email);
        }

 public interface IRepository<T, ID> where T : IAggregateRoot
    {
        T GetById(ID id);
        List<T> GetAll();
        T Save(T entity);
        T SaveOrUpdate(T entity);
        void Delete(T entity);
        void Flush();
}

Так в чем же преимущества. Есть огромные! Как вы можете видеть для интерфейса IRepository, мы разрешаем только IAggregateRoot иметь репозиторий (руководство DDD). Все удаляемые репозитории будут называться «Удалить» (ни один разработчик не назовет его «Удалить» и т. Д., И его можно реализовать только в одном месте, класс GenericNHibernate). Если разработчик в моей команде хочет создать новый репозиторий для сущности, единственный код -

открытый класс CustomerRepositoryNHibernate: GenericNHibernateRepository, ICustomerRepository {}

Затем вы читаете, удаляете, находите функции ... вы называете это. Неплохо.

Но еще одно превосходное преимущество, если вы используете Dependency Injection и IoC framework, я могу просто сказать, что, например, с помощью Windsor Castle вы можете создать средство, которое загружает все репозитории, которые реализуют интерфейс IRepository и расположены в сборке (например, MyProject.Infrastructure). .Данные). Это дает вам экстремальный импульс для вашей команды.

Сначала ваш разработчик создает новый репозиторий в MyProject.Infrastructure.Data со строкой кода, как в примере выше.

Второй при запуске приложения объект Windsor Castle сделает его доступным для инъекции. Таким образом, ваш разработчик может просто продолжать писать контроллер или класс обслуживания, который занимает IComnpanyRepository в качестве параметра конструктора и все это там.

0 голосов
/ 31 мая 2011

Я думаю, вы должны использовать шаблон GenericRepository и Specification. Это избавит вас от использования множества специализированных методов в каждом хранилище.

...