Pull to refresh
2
0.1
Drone @dorne

User

Send message
Например, подготовку контейнера, в который кладётся 100500 данных (включая погоду на марсе), я бы вынес в отдельную функцию.

Это и вынесено в отдельную функцию. BuildTop сама ничего помимо этого не делает. Сама логика вынесена в Method Object. В контейнер кладется не всё (включая погоду на марсе), а только данные в контексте. Этот набор не может быть шире набора параметров метода. Собственно на параметры метода интерфейса и навешиваются аттрибуты.

А ещё можно полунастроенные контейнеры передавать в функции, чтобы повторно не настраивать для множества вызовов с одинаковыми доп. параметрами. В таких сценариях метод, вызывающий сервис, не будет содержать в своём теле вызовы RegisterInstance.

Ничего не понял. Нужен пример.
Такая проблема есть.
В классе который должен инжектировать данные в контейнер можно забыть инжектировать данные. На это можно написать валидатор, который будет проверять наличие в теле метода вызова Register.

Доставать же из контейнера данные если они не нужны конкретной реализации собственно и не нужно.
Компонент, который получает в качестве параметра контекст только потому что компоненту, который он использует, необходимо передать контекст от компонента, который пользуется этим. Я считаю, что это ужасно.

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

Я думаю, что мы прекрасно поняли позиции друг друга, это хорошо, а я не претендую на истину в последней инстанции :-).
Лучше. В этом случае знание односторонне — все знают о контексте, контекст не знает ни о ком

А ещё все знают о том, что все знают о контексте, и что его надо всем передавать…

Собственно, возвращаясь к вопросу: а смысл атрибутов тогда?

Это способ документирования кода. Эти аттрибуты нужны в качестве спецификации для разработчика.
Статической быть не может,

Кстати, на этот счет я погорячился. Её можно сделать. Но пока её нет :-)
Ну и да, какой с этих атрибутов толк? У вас есть статическая проверка того, что при любой активации зависимости эти данные вброшены в контекст

Статической быть не может, а динамическую делает сам контейнер. Также как нет статической проверки корректности конфигурации контейнера, но есть статическая проверка корректности вызова конструктора через new.

А вообще — двусторонняя связанность, потребитель знает о зависимости, а зависимость знает о том, что потребитель в нее вбросит. Как раз то, чего IoC пытается избежать.

Я знаю, что это плохо. Но передача контекста параметром с этой точки зрения не лучше. Одному компоненту прийдется знать что надо передавать контекст, а другому его получать. Этого не избежать.
Чего я избежал — так это необходимости сообщать об этой зависимости всем посредникам между ITopBuilder и IRanker. К таковым может относиться композит из всех реализаций IRanker.
Ну то есть вы все равно где-то явно определили этот набор данных. Причем в потребителе зависимости (т.е., том месте, о котором зависимость знать не должна).

Да. Методы интерфейсов, выполнение которых подразумевает инжектирование данных (BuildTop) помечаеются аттрибутами говорящими «Я инжектирую это, это и это».
Интерфейсы компонентов, реализация которых подразумевает разрешение данных из контейнера (IRanker) помечаются аттрибутом «Я ожидаю данные этого, этого и этого типов из контейнера».

Тому, кто реализует IRanker не нужно знать кто эти данные инжектирует, но это всегда можно узнать по парным аттрибутам.
Погода на Марсе — тоже?

Нет. Только то что передано в качастве параметров методоу BuildTop
Каким контрактом?

Описанием метода BuildTop и соответствующими аттрибуттами на его параметрах, которые я, к сожалению, оставил, за рамками поста.
Юнит-тесты тут вообще не при чем, корректность вбрасывания проверяется интеграционными.

Корректность передачи контекста тоже интеграционными?
Я говорю про тесты на способность реализации метода BuildTop выполнять его функцию. Если теперь, из-за использования Data Injection они стали интеграционными, то ок.

По факту, это означает, что вы используете обычный контекст, просто извращенным способом.

Смысл называть это отдельным шаблоном?

Этот шаблон решает ту же проблему что и контекст, но на мой взгляд, делает это удобнее. Но решает он её иначе. Поэтому это отдельный шаблон.
Вот только вам надо не забыть вбросить данные в контейнер (не имея никакой конкретной информации о том, какие именно данные нужны потребителям)

Поэтому вбрасываются все данные которые есть. А потребители сами разбирутся, что им нужно. Благо список всего, что им можно получить четко обозначен контрактом.
при этом не забыть породить все потребители именно в этом контейнере.

Об этом трудно забыть. Т.к. компонент в этом случае не заработает в принципе, даже если данные не нужны никому. И не пройдет ни один юнит тест.

По сути, вы используете дочерний контейнер как контекст-бэг.

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

Когда операция становится частью чего-то большего появляется контекст контекста, а потом контекст контекста контекста.
Алгоритм конкретного IRanker зависит от этого.

Да. Но мы хотим зависеть только от обстракции.

Вы все равно это передаете. Просто не в вызов, а в конструктор. Суть от этого не меняется.


Я данные не передаю. Я позволяю любой конкретной реализации получить эти данные, если ей это нужно. Происходит инверсия управления.
Да.
С точки зрения абстракции мне удобнее не знать, какие именно данные нужны конкретному IRanker чтобы выставить оценку. Это не имеет для алгоритма ранжирования никакого значения. Зачем же я должен передавать в качестве параместра всё что может понадобиться какой-то из реализацй, но скорее всего не понадобится?
Не для сокрытия ли этого как раз и нужен IoC?

Я всегда думал, что смысл DI не в конструировании объектов. С этим прекрасно справляются обычные фабрики. Я всегда думал, что DI нужен для того, чтобы позволить компоненту ничего не знать про то, от чего зависит компопент, от которого он сам зависит (я говорю про зависимости зависимостей).
Это аналогично принципу «вассал моего вассала — не мой вассал» и сильно упрощает жизнь.

Делегирование конструирования объектов на контейнер, это то, чем мы платим (да это цена, ибо это не очевидно) за избавление от проблемы зависимостей зависимостей, и многих других.
Они, так же как и плюсы Dependency Injection становятся отчетливее, когда зависимостей по данным становится очень много.
Передача лишнего параметра в данном случае видится мне аналогией конструирования объекта через new с передачей параметра. Это нормально, до тех пор, пока мы не ловим себя на том, что нам приходится разрешать параметры параметров и параметры параметров параметров, чтобы передать их в конструктор.
Я считаю, что понять Data Injection не сложнее, а плюсы тоже есть. Для меня они иногда (не всегда) перевешивают.
То же самое я думаю и я.
Когда-то при чтении кода вы впервые столкнулись с Dependency Injection, и, скорее всего, впервые столкнувшись с ним, вы на мгновение подумали, что это не просто и не очевидно.
Только в первый раз ;-)
при кривой конфигурации


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

А это (доступ ко внешним данным) кому-то нужно? А вот прозрачность системы вы резко понизили, что на архитектуре сказывается отрицательно.


Если доступа ко внешним данным никому не нужно, то я не рекомендую применять описаный шаблон. Даже запрещаю это делать.
Если же всё-таки он нужен, то компонент который инжектирует данные должен быть соответствующем образом отмечен, как и компонент, реализация которого допускает импорт данных из контейнера c явным указанием всех таких типов данных. Например, аттрибутами.

Information

Rating
3,564-th
Location
Москва, Москва и Московская обл., Россия
Registered
Activity