Комментарии 12
С критикой фабрик вы свернули куда-то не в ту сторону.
Во-первых, первый пример из документации — это анти-пример, поясняющий как нельзя делать:
However, the above code is an example of an anti-pattern. This will work, and you can use the container to get access to all other classes in your app, however if you do this you will not really be taking advantage of the power of dependency injection. This is known, by the way, as Service Locator Pattern.
Во-вторых, если класс знает о фабрике, а фабрика знает о контейнере — это еще не означает что класс знает о контейнере. Да, явное использование классов из библиотеки означает что теперь нельзя так просто взять и сменить библиотеку, но SRP при этом не нарушается!
Ну а если не нравится использование конкретных классов как зависимостей — то вот подходящий раздел: Using IFactory directly. Такую фабрику потенциально можно использовать и вовсе без контейнера.
То же самое касается и ITickable — да, контейнер теперь знает про все ITickable-компоненты. Но интерфейс остается просто интерфейсом, и никто не мешает его использовать и без контейнера.
Во-вторых, если класс знает о фабрике, а фабрика знает о контейнере — это еще не означает что класс знает о контейнере. Да, явное использование классов из библиотеки означает что теперь нельзя так просто взять и сменить библиотеку, но SRP при этом не нарушается!
Того, что фабрика знает о контейнере уже достаточно, чтобы делать вывод о завязке на контейнер и о том, что контейнер начинает управлять кратко-срочными зависимостями, чего делать не должен.
Использование ITickable и IFactory также завязывает проект на контейнер, в силу того, что код этих интерфейсов реализован в коде Zejnect.
Касаемо ITickable — можно оставить интерфейс и его можно использовать без контейнера, но тогда нужна собственная реализация класса, который будет обрабатывать все ITickable
Я не утверждаю, что использование контейнера в 2-3 фабриках по проекту приведет все к бедственному состоянию, но это уже сигнал о том, чтобы задуматься
Если контейнер начинает все чаще появляться в коде самого приложения
… но ведь он при подходе с фабриками не будет появляться в коде приложения за пределами Composition Root.
а также чревато плавным переходом от контейнера к локатору сервисов
Не могу представить ни одного сценария, когда увеличение использования фабрик плавно превращается в сервис-локатор. Это два совершенно разных паттерна.
… но ведь он при подходе с фабриками не будет появляться в коде приложения за пределами Composition Root.
Получается, что сама фабрика зашита в контейнер, пусть и неявно.
Не могу представить ни одного сценария, когда увеличение использования фабрик плавно превращается в сервис-локатор. Это два совершенно разных паттерна.
Передача контейнера в фабрику в данном контексте выступает как первый шаг к тому, чтобы позволить себе передать контейнер в другие классы. Но ему и в фабрике не место.
Статья по сути своей хороша лишь тем, что указаны проблемы Zenject с точки зрения DI. Написано, что плохо, и как делать не стоит. Но не написано, как делать стоит в каждом конкретном случае)
Как стоит делать в каждом конкретном случае описать невозможно.
Мне повезло познакомится с Simple Injector в качестве первого контейнера, рекомендую почитать основные принципы (англ.). Идеальное руководство чтобы правильно понять контейнеры.
Design Principles
Design Decisions
Кстати он еще и внутри адекватно сделан и поэтому быстро работает (advanced)
Simple Injector Pipeline
ps: не спешите переводить проект на юнити на Simple Injector, он использует кодогенерацию и не заведется под iOS
Проблема только в криворукости разработчиков и их опыте.
Знать бы где упасть, да соломки бы подстелить. Узнать о своей криворукости зачастую получается уже собрав все грабли.
Плохо, когда фреймворк подталкивает к использованию плохих практик (это я про инжекцию куда-либо кроме конструктора), и хорошо когда выходят статьи которые поднимают этот вопрос.
Zenject: Как IoC контейнер может убить Внедрение Зависимостей на вашем проекте