Я использую Unity в качестве движка внедрения зависимостей.Он содержит интерфейсы / классы для классов «репозиторий» и «менеджер».Эти репозитории отвечают за получение / сохранение / обновление данных из / в БД, и менеджеры «знают» об отношениях объектов с другими компонентами / классами.
Существует фабрика, реализованная для получения экземпляра контейнера зависимостей (1 экземпляр на запрос).Когда создается какой-либо класс репозитория / менеджера, он получает контейнер зависимостей в качестве параметра конструктора и может создавать все другие менеджеры / репозитории при необходимости.
Существует 2 способа создания бизнес-сущностей:
- Когда данные извлекаются из репозитория БД, они создают экземпляры объектов и инициализируют их с соответствующими данными БД, среди прочего поле «Контейнер»инициализируется.
- Когда объект создается в коде, который должен быть помещен в БД среди прочего, он принимает параметр «IUnityContainer».
В результате в обоих случаях любой бизнес-объект имеет контейнер зависимостей внутри иесли ему нужно получить какие-либо данные, он может получить экземпляр соответствующего менеджера и запросить требуемые данные.
Постановка задачи: на прошлой неделе я прочитал несколько вопросов / ответов по SO, в которых говорится что-то вроде этого:
- экземпляры объектов не должны иметь доступа к контейнеру зависимостей;
- вместо этого они должны получать все необходимые интерфейсы в конструкторе.
Угадайте, то же самое применяется для менеджера / хранилищаклассы: я не должен передавать экземпляр контейнера их конструктору, вместо этого я должен поместить интерфейсы для других необходимых компонентов.
Для меня это кажется разумным, но:
Мне понадобится, чтобы любой объект предоставил ВСЕ интерфейсы, которые ему нужны (обычно каждому менеджеру / репозиторию / объекту нужно 3-5 из них);
В большинстве случаев требуется только 1-2 интерфейса (поэтому я не хочу создавать много других);
Вопрос 1 : Это действительно хороший подход, чтобы «спрятать» контейнер?Зачем?(на самом деле, я чувствую, что знаю почему, но если у вас есть хороший ответ, пожалуйста, сообщите).
Вопрос 2 : Какова хорошая практика для решения такой проблемы?
Вопрос 3 : В моей конкретной реализации, когда мои объекты извлекаются из БД (я использую Linq2Sql и думаю о переходе на EF), я не могу создавать объекты с помощью DependencyContainer, я должен сделать это сам (потому что объектысозданный с использованием выражения, которое выполняется на сайте SQL, будет вызван конструктор без параметров с последующими данными, присвоенными общедоступным свойствам, а контейнер зависимостей недоступен на стороне SQL).Есть ли обходной путь для этого?
Технические подробности моей реализации:
Пример конструктора базового класса Manager:
public abstract class ManagerBase : IManager
{
protected ManagerBase(IUnityContainer container)
{
DependancyContainer = container;
}
protected readonly IUnityContainer DependancyContainer;
...
}
Пример базового класса репозитория:
public abstract class RepositoryBase<T, TDb> : IRepository<T>
where T : IEntity
where TDb : class, IDbEntity, new()
{
protected abstract ITable<TDb> GetTable();
public IQueryable<T> GetAll()
{
return GetTable().Select(GetConverter());
}
Пример извлечения данных из БД: репозиторий создает экземпляры объектов и инициализирует их с соответствующими данными БД, среди прочего инициализируется поле «Контейнер»:
public class CountryRepository
: RepositoryBase<ICountry, DbData.Country>, ICountryRepository
{
protected override Expression<Func<DbData.Country, ICountry>> GetConverter()
{
return dbEntity => new Country
{
DependancyContainer = DependancyContainer,
Code = dbEntity.CountryCode,
Name = dbEntity.CountryName,
};
}
Вызывается следующеекогда данные необходимо получить из БД:
public class CountryManager : ManagerBase
{
ICountry GetCountryById(int countryId)
{
ICountryRepository repository = DependancyContainer.Resolve<ICountryRepository>();
return repository.GetAll()
.Where(country=>country.Id==countryId)
.SingleOrDefault()
;
}
}