Шаблон репозитория Стандартизация методов - PullRequest
35 голосов
/ 21 апреля 2010

Все, что я пытаюсь найти правильное определение шаблона хранилища.

Мое первоначальное понимание было таким (чрезвычайно тупым)

  • Отделите ваши бизнес-объекты от ваших объектов данных
  • Стандартизировать методы доступа на уровне доступа к данным.

Я действительно видел 2 разных реализации, и в Интернете нет формальных примеров, те, которые я видел, спрятаны в книгах.

Реализация 1:

public Interface IRepository<T>{
      List<T> GetAll();
      void Create(T p);
      void Update(T p);
}


public interface IProductRepository: IRepository<Product> {
      //Extension methods if needed
       List<Product> GetProductsByCustomerID();
}

Реализация 2:

public interface IProductRepository {
      List<Product> GetAllProducts();
      void CreateProduct(Product p);
      void UpdateProduct(Product p);
      List<Product> GetProductsByCustomerID();
}

Обратите внимание, что первый - это общий Get / Update / GetAll и т. Д., Второй - больше того, что я определил бы как "DAO".

Оба разделяют извлечение из ваших сущностей данных. Что мне нравится, но я могу сделать то же самое с простым DAO. Тем не менее, вторая часть стандартизирует операции доступа, в которых я вижу ценность, если вы внедрите этот корпоративный подход, люди легко узнают набор методов доступа для вашего хранилища.

Не ошибаюсь ли я, что стандартизация доступа к данным является неотъемлемой частью этой модели? Если оба они верны, почему бы выбрать вариант 2?

Rhino имеет хорошую статью о реализации 1, и, конечно, MS имеет расплывчатое определение , а пример реализации 2 - здесь .

Ответы [ 7 ]

16 голосов
/ 27 апреля 2010

Я вторая цитата Фаулера, на которую ссылается Одед. Я хочу отметить, что он сказал "collection- like " interface. Как реализовать интерфейс, подобный интерфейсу коллекции, зависит от вас, но вы не можете и не должны пытаться скрыть тот факт, что он представляет собой удаленный источник данных. Поэтому он значительно отличается от коллекции в памяти, которая не требует сброса изменений в удаленное хранилище данных. Механизм отслеживания изменений вашего ORM или вашего собственного решения определяет, насколько прозрачным это может быть сделано для звонящего. Удаления, как правило, должны быть помечены явно, вставки могут быть обнаружены (постоянство по достижимости), а обновления иногда также должны быть помечены также явно. Объедините это со сложными зависимостями ваших агрегатных корней, и вы увидите, что это не очень похоже на коллекцию.

Нет такой вещи как "каноническая реализация репозитория".

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

Убедитесь, что вы понимаете значение каждого подхода, прежде чем решить, какой путь выбрать. Грег Янг имеет хороший пост о достоинствах общих репозиториев.

http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx

7 голосов
/ 21 апреля 2010

У Мартина Фаулера (Martin Fowler) «Шаблоны архитектуры корпоративных приложений» определение шаблона репозитория:

. Передается между слоями домена и слоями отображения данных с использованием интерфейса, подобного коллекции, для доступа к объектам домена.

Итак, оба подхода верны.

4 голосов
/ 21 апреля 2010

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

Я рекомендую, чтобы ваш разработчик IProductRepository получил доступ к универсальному IRepository<Product> через делегирование и внедрил его через конструктор, чтобы вы могли составить свой класс из множества IRepositories и сгруппировать их за одним интерфейсом таким образом, который имеет смысл.

Я написал блог на эту тему, хотя в нем конкретно упоминается NHibernate, этот шаблон можно применять к любому типу репозитория: Создание общего универсального и расширяемого репозитория NHiberate версии 2

2 голосов
/ 27 апреля 2010

С появлением LINQ в .NET универсальный шаблон хранилища становится намного проще реализовать:

public interface IRepository<T> : IQueryable<T>
{
    void Add(T item);
    void Remove(T item);
}

Чтобы считаться репозиторием, ему просто необходимо иметь доступ к данным в базовом хранилище (легко предоставляемое IQueryable) и изменять содержащиеся в нем данные.

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

1 голос
/ 27 апреля 2010

В дополнение к вашему общему интерфейсу репозитория (реализация 1) и вашему варианту в отношении репозитория для конкретной роли (реализация 2) вы также можете рассмотреть репозиторий универсального метода:

public interface IRepository
{
    void Save<ENTITY>(ENTITY entity) where ENTITY : DomainEntity;

    ENTITY Load<ENTITY>(Guid id) where ENTITY : DomainEntity;

    IQueryable<ENTITY> Query<ENTITY>() where ENTITY : DomainEntity;

    IQueryable<ENTITY> Query<ENTITY>(IDomainQuery<ENTITY> whereQuery)
        where ENTITY : DomainEntity;
}

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

0 голосов
/ 31 июля 2013

Шаблон репозитория является одним из наиболее часто используемых шаблонов в разработке программного обеспечения. Есть много постов, которые можно пометить как ответ на ваш вопрос. Что я хотел бы отметить, так это то, что хорошая реализация репозитория будет улучшена, если вы используете IoC (Autofac, Windsor и т. Д.) Я давно играл с некоторыми платформами на основе ADO.NET (LinqToSql, EF) и NHibernate. Вы всегда можете получить выгоду от универсальной реализации, если используете IoC. Вы можете определять интерфейсы для своих конкретных репозиториев и разрешать их, когда вам действительно нужны определенные действия.

0 голосов
/ 25 ноября 2011

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

Примерно так:

public Interface IRepository<T>{
  List<T> GetAll();
  void Create(T p);
  void Update(T p);
}


public interface IProductRepository {
  //Extension methods if needed
   List<Product> GetProductsByCustomerID();
   List<T> GetAll();
   void Create(T p);
   //Let assume here you should not be able to update the products
}

public ProductRepository : IProductRepository {
    private IRepository _repository;

    public ProductRepository(IRepository repository) {
        this._repository = repository;
    }

       List<T> GetAll() 
       {
            _repository.GetAll();
       }

       void Create(T p) 
       {
            _repository.Create(p);
       }

       List<Product> GetProductsByCustomerID() 
       {
          //..implementation goes here
       }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...