TL; DR: Мы должны внедрить зависимости в классы, которые в них нуждаются.Классы не должны нести ответственность за предоставление зависимостей своим зависимостям.
Если MainClass
получает userId
и sessionId
откуда-то, как он их получает?Предположительно они вводятся в MainClass
, или вводится что-то, что обеспечивает их.
Если MainClass
получает их посредством инъекции, UtilityRepository
может получать их таким же образом.Если MainClass
не получает их через инъекцию, сконфигурируйте ваш контейнер так, чтобы они все равно вводили в UtilityRepository
Это может выглядеть так:
public interface IContext // not the greatest name
{
string UserId { get; }
string SessionId { get; }
}
или
public interface IContextAccessor
{
// where Context is an object containing the values you need.
Context GetContext();
}
Затем вы конфигурируете контейнер, предоставляющий реализацию во время выполнения IContextAccessor
, которая извлекает значения из текущего запроса.Внедрить IContextAccessor
в UtilityRepository
.
public class UtilityRepository : IUtilityRepository
{
private readonly IContextAccessor _contextAccessor;
public UtilityRepository(IContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
}
Если MainClass
эти значения не нужны (он только получал их, поэтому мог передавать их чему-то другому), то он не должен их получать,Если MainClass
нуждается в них, тот факт, что UtilityRepository
также нуждается в них, является случайным.(Вы также можете ввести IContextAccessor
в MainClass
.) Нет причины, по которой MainClass
должен отвечать за передачу их в UtilityRepository
.
MainClass
зависит от абстракции - IUtilityRepository
.Он не знает и не должен знать, от чего зависит конкретная реализация этого интерфейса.Он не должен знать ничего, чего нет в этом интерфейсе.Как только он это сделает, он больше не «зависит» от интерфейса.Это связано с реализацией.
Это одно из основных преимуществ использования контейнера IoC.Классы получают свои зависимости от контейнера, а не друг от друга.Зависимость от абстракций означает, что классы не знают, как эти абстракции реализованы.Это, в свою очередь, означает, что классы не знают о зависимостях из их зависимостей.
Чтобы проиллюстрировать: лампа зависит от абстракции - розетка, которая получает свою мощностьот где-то. Это может быть электрическая сеть, солнечная батарея, генератор, велосипед или что-то еще.
Независимо от реализации источника питания, он, вероятно, имеет свои собственные зависимости.Генератору нужен бензин.Электросети нужна электростанция.
Эти зависимости, вероятно, имеют свои собственные зависимости.Электростанции нужен кто-то, чтобы копать уголь.
Лампа не должна ничего знать об этих зависимостях.Если используется лампа, значит:
- Подключите лампу
- Включите лампу
- Подайте газ в генератор
Затеммы больше не зависим от абстракции.Мы зависим от генератора.Неважно, если мы объявим его как интерфейс и назовем его IPowerSupply
.Единственная реализация, с которой он может работать, - это генератор.
То же самое относится и к электросети.Это зависит от источника питания.Для этого источника энергии могут потребоваться уголь, генераторы и т. Д. Но что произойдет, если мы возьмем на себя ответственность за запуск генератора, а затем позже заменим генератор на массивную панель солнечных батарей?Как электросеть запустит генератор, когда генератора нет?
Вот почему каждый класс должен знать как можно меньше о своих зависимостях.Если он что-то знает, он связан с этой деталью.Весь смысл инверсии зависимости (в зависимости от абстракций) состоит в том, чтобы предотвратить или минимизировать связывание, чтобы изменение одной детали реализации не имело волнового эффекта, заставляющего нас изменять другие вещи, которые не должны были бы меняться.
Контейнеры IoC позволяют нам сделать это очень легко.Каждый класс говорит, что ему нужно, требуя его в конструкторе, а контейнер вводит его.Если внедренная вещь имеет свои зависимости, об этом позаботится и контейнер.Все наши классы создаются независимо, ничего не зная друг о друге.