Является ли репозиторий синглтон или статический или ни один из них?

У меня есть веб-сайт ASP.NET, который использует проект, управляемый доменами, и использует репозиторий для своих операций с базой данных.
Я хочу знать, что такое плюсы и минусы репозитория singleton и статического репозитория и простого класса репозитория, который будет новым при каждом доступе?
еще больше, если кто-нибудь может сравнить и направить меня к использованию, какой из них я буду признателен.

Ответ 1

Статический и singleton не являются хорошим решением для шаблона репозитория. Что делать, если ваше приложение будет использовать 2 или более хранилища в будущем?

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

Я предлагаю вам прочитать хорошую книгу о дизайне, ориентированном на домен, и хорошую книгу об инъекции зависимостей (например, Mark Seeman Dependency Injection in.NET).


С синглтонами и статическими классами ваше приложение не будет масштабируемым

У вас есть два одноэлементных репозитория:

class Repository<TEntity> {

  static Repository<TEntity> Instance { get { ... /*using sql server*/ } }
}

class Repository2<TEntity> {

  static Repository2<TEntity> Instance { get { ... /*using WCF or XML or any else */ } }
}

Службы, использующие их, должны иметь статическую ссылку на одну из них или на оба:

class OrderService {

    public void Save(Order order) { Repository<Order>.Instance.Insert(order); }
}

Как вы можете сохранить свой заказ с помощью Repository2, если репозиторий статически ссылается?

Лучшее решение использует DI:

interface IRepository<TEntity> { ... }

class SqlRepository<TEntity> : IRepository<TEntity> { ....}

class OrderService {
    private readonly IRepository<TEntity> _repo;

    public OrderService(IRepository<TEntity> repo) { _repo = repo; }

    public void Save(Order order) { repo.Insert(order); }
}

Ответ 2

Не используйте статические или одноэлементные репозитории из-за:

  • Это влияет на testablility, вы не можете издеваться над ним при модульном тестировании.

  • Это влияет на расширяемость, вы не можете сделать более одной конкретной реализации, и вы не можете заменить поведение без повторной компиляции.

  • Это влияет на масштабируемость с точки зрения управления жизненным циклом, insetead зависит от структуры инъекции зависимостей, чтобы вносить зависимость и управлять жизненным циклом.

  • Он влияет на ремонтопригодность, он заставляет зависимость от конкретной реализации вместо абстракции.

Нижняя строка: DONT использует статические или одноэлементные репозитории

вместо этого создайте интерфейсы репозитория в вашем проекте модели домена и реализуйте эти интерфейсы в конкретном проекте доступа к данным и используйте инфраструктуру впрыска зависимостей.

Ответ 3

Два SOLID причины не иметь одноэлементного репозитория:

  • Потребители репозитория будут связаны с реализацией репозитория. Это негативно скажется на расширяемости и тестируемости. Это нарушение DIP. Зависит от абстракций, а не от конкреций.

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

Возможное решение обеих проблем: Инъекция конструктора.

Ответ 4

Я лично с уважением не согласен с предыдущими ответами.

Я разработал несколько веб-сайтов (один с 7 миллионами просмотров страниц в месяц) и никогда не имел ни одной проблемы с моими статическими репозиториями.

Моя статическая реализация репозитория довольно проста и содержит только объекты-поставщики в качестве свойств. Один репозиторий может содержать столько поставщиков, сколько вам нужно.

Затем поставщики отвечают за управление подключением к базе данных и транзакциями. Используя TransactionScope, потребитель мог управлять транзакциями или предоставлять их поставщикам.

Каждый поставщик разрабатывается с использованием шаблона singleton.

Таким образом, я могу получить свои объекты, просто называя это:

var myObj = MyRepository.MyProvider.GetMyObject(id);

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

Я не вижу, где мои пользователи репозитория/провайдеров связаны с моим репозиторием. Фактически, реализации моих провайдеров полностью абстрагированы от них. Конечно, все провайдеры, возвращаемые моим репозиторием, являются интерфейсами, и я мог бы легко изменить их реализацию в любое время и направить мою новую dll на веб-сервер. Если я хочу создать совершенно новый провайдер с тем же интерфейсом, мне нужно изменить его только в одном месте: мой репозиторий.

Таким образом, не нужно добавлять инъекцию зависимостей или создавать собственный ControllerFactory (для MVC-программ).

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

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