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()
, чтобы предоставить новый элемент списка конструктору.