Инверсия управления, инъекция зависимостей с SRP и отложенная загрузка
Мы с коллегой-разработчиком обсуждаем (мягко говоря) ленивую загрузку свойств объекта.
- Он говорит использовать статический вызов поиска IoC для разрешения и отложенной загрузки объектов объекта.
- Я говорю, что нарушает SRP, и использует собственный сервис для разрешения этого объекта.
Итак, как бы вы справились с Lazy-Loading после IoC и SRP?
Вы не можете выполнить модульное тестирование этого свойства с отложенной загрузкой. Он опровергает тот, который говорит: "У вас уже есть модульные тесты для UserStatsService - там есть покрытие кода". Действительная точка, но свойство остается непроверенным, хотя для "полного" покрытия.
Настройка / шаблоны кода:
- В проекте используются строгие правила внедрения зависимостей (вводятся в каталогах всех сервисов, репозиториев и т. Д.).
- Проект использует IoC через Касл (но может быть что угодно, например, Unity).
Пример ниже.
public class User
{
public Guid UserId { get; set; }
private UserStats _userStats;
// lazy-loading of an object on an object
public UserStats UserStats
{
get
{
if (_userStats == null)
{
// ComponentsLookup is just a wrapper around IoC
// Castle/Unity/etc.
_userStats =
ComponentsLookup
.Fetch<UserStatsService>()
.GetByUserId(this.UserId);
}
return _userStats;
}
}
}
Выше показан пример отложенной загрузки объекта. Я говорю не использовать это, а получить доступ к UserStatsService из уровня пользовательского интерфейса, где бы вам ни понадобился этот объект.
РЕДАКТИРОВАТЬ: Один ответ ниже напомнил мне трюк NHibernate с ленивой загрузкой, которая заключается в виртуализации вашей собственности, позволяя NHibernate создать перегрузку самой ленивой загрузки. Отлично, но мы не используем NHibernate.
Никто на самом деле не занимается проблемой Lazy-Loading. Некоторые хорошие статьи и ТАК вопросы близки:
- Использование структур внедрения Dependency Injection для классов с множеством зависимостей
- http://blog.vuscode.com/malovicn/archive/2009/10/16/inversion-of-control-single-responsibility-principle-and-nikola-s-laws-of-dependency-injection.aspx
Я вижу выгоду ленивой загрузки. Не поймите меня неправильно, все, что я делал, было ленивой загрузкой моих сложных типов и их подтипов, пока я не переключился на DI-способы ниндзя. Преимущество в уровне пользовательского интерфейса, где статистика пользователя отображается, скажем, в списке из 100 строк. Но с DI теперь вы должны ссылаться на несколько строк кода, чтобы получить статистику этого пользователя (чтобы не нарушать SRP и не нарушать закон Деметры), и он должен пройти этот длинный путь поисков более 100 раз.
Да, да, добавление кэширования и обеспечение того, что UserStatsService закодирован для использования в качестве шаблона Singleton, значительно снижает затраты производительности.
Но мне интересно, есть ли у кого-нибудь еще [упрямый] разработчик, который просто не будет полностью подчиняться правилам IoC и DI, и имеет действительные точки производительности / кодирования, чтобы оправдать обходные пути.
1 ответ
Сами сущности не должны нести ответственность за ленивую загрузку. Это инфраструктурная проблема, решение которой будет лежать в другом месте.
Допустим, сущность используется в двух разных контекстах. Во-первых, его дети используются интенсивно и загружены. Во втором они используются редко и загружаются ленивыми. Это также проблема организации? Как будет выглядеть конфигурация?
NHibernate отвечает на эти вопросы, передавая тип сущности. Свойство типа IList<Entity>
устанавливается инфраструктурой для реализации, которая знает о отложенной загрузке. Сущность остается в блаженном неведении. Родительские ссылки (как в вашем вопросе) также обрабатываются, требуя только простого свойства.
Теперь, когда проблема находится за пределами сущности, инфраструктура (ORM) отвечает за определение контекста и конфигурации (например, нетерпеливую / отложенную загрузку).