DI Framework: как избежать непрерывной передачи внедренных зависимостей вверх по цепочке и без использования сервисного локатора (особенно с Ninject)

Мне нужно немного больше помочь "получить", как инфраструктура DI, как Ninject, проходит мимо основ.

Возьмите образец Ninject:

class Samurai {
private IWeapon _weapon;

    [Inject]
    public Samurai(IWeapon weapon) {
      _weapon = weapon;
    }

    public void Attack(string target) {
      _weapon.Hit(target);
    }
 }

Без рамки DI (т.е. ссылки [Inject] выше) ссылочный класс будет выглядеть примерно так:

class Program {
   public static void Main() { 
    Samurai warrior1 = new Samurai(new Shuriken());
    Samurai warrior2 = new Samurai(new Sword());
    warrior1.Attack("the evildoers");
    warrior2.Attack("the evildoers");
  }
}

... где вы обновляете все. Да, вы удалили зависимость в самурае, но теперь у вас есть зависимость на один шаг дальше по цепочке. Простой.

С помощью Ninject вы избавляетесь от новичка всего:

class Program {
  public static void Main() {
    IKernel kernel = new StandardKernel(new WarriorModule());
    Samurai warrior = kernel.Get<Samurai>();
    warrior.Attack("the evildoers");
  }
}

ОДНАКО, это моя путаница: не создавая своего рода сервис-локатор, чтобы заботиться о том, чтобы эффективно обновлять применимое ядро ​​и модуль (т.е..IoC.TypeResolver.Get < > ()), что: a) лучший способ не иметь новых ядер во всем мире (ссылки на локатор обслуживания повсюду?), и б) более важно, когда у вас есть длинная длинная цепочка с зависимостями с собственными зависимостями, вы делаете это до крайности проходящих инъекций все, что я уверен, является серьезным анти-шаблоном (друг назвал его "инъекцией зависимостей с горячей картофелем" ).

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

Дальнейшее загрязнение воды для меня - это использование каркаса DI, что лучший способ справиться со сценарием, в котором ссылочный класс нуждается в IList, который обычно помещается в конструктор (т.е. новый ReferencedClass (myList)) как таковой, кроме как в простых случаях, таких как строка подключения строки базы данных, не летает. Просто создайте свойство и настройте его после его открытия/установки службы DI Framework? То есть

var referencedClass = IoC.Get<IReferencedClass>();
referencedClass.MyList = myList;

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

Ответы

Ответ 1

Что касается проблемы зависимости "горячего картофеля", этого не должно произойти. Рамка внедрения зависимостей предназначена для вас.

Например, если Class1 имеет зависимость от Class2, а Class2 имеет зависимость от класса 3, вам не нужно вводить Class3 в Class1, чтобы соответствовать зависимости класса 2. Ядро пойдет вниз по цепочке зависимостей для вас и автоматически разрешит зависимые потоки (пока все классы в игре были зарегистрированы в ядре), когда вы запрашиваете Class1.

Класс1 зависит от класса 2, зависит от класса 3

Конструктор Class1 не должен вообще упоминать Class3.

Что касается второго вопроса, то, как и как это устроено, зависит от структуры. С Ninject я думаю, вы можете использовать синтаксис Bind().To().WithConstructorArgument(), чтобы предоставить новый элемент списка конструктору.