Шаблон репозитория в asp.net mvc с linq to sql - PullRequest
1 голос
/ 02 августа 2010

Я читал код приложения NerdDinner и, в частности, Шаблон репозитория ... У меня есть один простой вопрос, касающийся этого блока

    public DinnersController()
        : this(new DinnerRepository()) {
    }

    public DinnersController(IDinnerRepository repository) {
        dinnerRepository = repository;
    }

Что если бы в каждом Ужине было, скажем,Категория ... мой вопрос

Вы бы также инициализировали репозиторий категорий в конструкторе класса ??

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

Буду признателен за понимание этого вопроса

Спасибо.

Ответы [ 5 ]

4 голосов
/ 02 августа 2010

То, что вы смотрите здесь, на самом деле не столько связано с шаблоном репозитория, само по себе , а больше связано с «внедрением зависимости», где внешние вещи, от которых зависит этот класс «вводятся» извне, а не создаются внутри (например, путем вызова new Repository()).

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

Это способствует правильной инкапсуляции и существенно улучшает тестируемость.

Тот факт, что вы не создаете экземпляры коллабораторов в классе, это то, что улучшает тестируемость (вы можете изолировать поведение класса, вводя экземпляры-заглушки или макеты при тестировании).

Ключевое слово здесь, когда речь идет о шаблоне хранилища, - это инкапсуляция. Шаблон репозитория берет все эти данные для доступа к данным и скрывает их от классов, использующих репозиторий. Даже если ORM может скрывать всю реальную работу CRUD, вы все равно связаны с реализацией ORM. Хранилище может выступать в качестве фасада или адаптера, предлагая абстрактный интерфейс для доступа к объектам.

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

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

В качестве альтернативы, вы можете предоставить фабричные классы как зависимости - опять же классы, которые реализуют некоторый фабричный интерфейс, но вместо самой зависимости это класс, который знает, как создать зависимость. Может быть, вы хотите другой IDinnerRepository для разных ситуаций. Фабрика может принять параметр и вернуть реализацию в соответствии с некоторой логикой, и, поскольку это всегда будет IDinnerRepository, контроллер не должен знать, что на самом деле делает этот репозиторий.

2 голосов
/ 02 августа 2010

Чтобы ваш код был разъединен, а контроллеры легко тестировались, вам нужно придерживаться внедрения зависимостей, поэтому либо:

public DinnersController() 
    : this(new DinnerRepository(), new CategoryRepository()) { 
} 

или менее элегантный

public DinnersController() 
    : this(new DinnerRepository(new CategoryRepository())) { 
} 
1 голос
/ 02 августа 2010

Я бы хотел, чтобы мои категории ужина были в моем хранилище.Но если они должны были быть отделены друг от друга, id поместите их обоих в ctor.

0 голосов
/ 02 августа 2010

Вы хотели бы передать это конструктору. Тем не менее, я бы не стал создавать какой-то конкретный класс, как это делается там.

Я не знаком с приложением NerdDinner, но думаю, что предпочтительным подходом является определение IDinnerRepository (и ICategoryRepository). Если вы выполняете кодирование с использованием интерфейсов и хотите переключиться, скажем, на XML-файл, базу данных MySQL или веб-службу, вам не нужно менять код контроллера.

Продвигая это на немного дальше, вы можете посмотреть на контейнеры IoC как ninject . Суть в том, что вы отображаете свой IDinnerRepository в конкретное приложение для реализации. Затем всякий раз, когда создается контроллер, вам предоставляется конкретный репозиторий (или любая другая зависимость, которая может вам понадобиться), даже если вы кодируете для интерфейса.

0 голосов
/ 02 августа 2010

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

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

Редактировать в ответ на комментарий:

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

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

Примечание : Это может помочь минимизировать хранилища, если у вас есть один репозиторий на Совокупный корень , а не на класс Entity.

...