Да, при кривой конфигурации в самом деле нет никакого выигрыша. Но в этом случае думать в первую очередь надо о том, что в проекте ещё кривое, кроме конфигурации. (Тот факт, что выигрыша не будет, если кто-то где-то ошибется не означает что его нет совсем и быть не может.)
А это (доступ ко внешним данным) кому-то нужно? А вот прозрачность системы вы резко понизили, что на архитектуре сказывается отрицательно.
Если доступа ко внешним данным никому не нужно, то я не рекомендую применять описаный шаблон. Даже запрещаю это делать.
Если же всё-таки он нужен, то компонент который инжектирует данные должен быть соответствующем образом отмечен, как и компонент, реализация которого допускает импорт данных из контейнера c явным указанием всех таких типов данных. Например, аттрибутами.
А ещё можно сделать так, чтобы для реализующего человека при одном взгляде на интерфейс, который он реализует стало понятно, что, лежащие в контейнере данные являются частью контракта, и на какие именно данные он в праве рассчитывать.
А сделать это очень просто…
Задача любого конкретного ранжировщика — выставить оценку команде. Какие данные нужны конкретному ранжировщику, это детали его реализации и к задаче реализации компонента не имеют. Это хорошая абстракция. Но, ранжировщикам потенциально могут потребоваться все данные, которые получает на вход в качестве параметров метод BuildTop. Применяя шаблон Data Dependency мы позволяем любой реализации ранжировщика получить доступ к этим данным, но не обязываем её это делать.
В случае, когда никому из ранжировщиков эти данные не нужны — Data Dependency применять не нужно.
Шаблон полезно иметь в арсенале на случай, если такое требование появится позже. В этом случае мы просто применим рефакторинг «Convert method to Method Object» и шаблон Data Dependency. Изменения интерфейса IRanker не потребуется. Таким образом, мы удовлетворим новое требование и сохраним совместимость с имеющимися реализациями.
И так я тоже решал эту задачу. С некоторыми оговорками:
«Композиция» реализовывала другой интерфейс, ибо результат подсчета композитного рейтинга не был целым числом. (В моем случае вообще не был числом).
В зависимости от используемого контейнера, может дополнительно понадобиться примитив поставщика оценщиков
Упомянутая возможность Unity мне хорошо известна и была использована в первую очередь. Проблема может возникнуть, если оценщики зависят друг от друга, именованые регистрации в Unity, к сожалению, друг о друге ничего не знают. Дефолтная реализация IRankerProvider делает именно то, что вы написали — разрешает массив. Но, сам интерфейс делается для того, чтобы поведеление можно было изменить. Можно ещё зарегистрировать InjectionFactory для массива. Как говорится, по желанию и никакого приведения типов.
BuilerWorker в даной ситуации больше похож на паттерн «MethodObject» и ничто не мешает его тестировать, при соответствующем изменении видимости.
Моим примером я избавила вас как минимум от двух не нужных компонентов:
закрытого и не тестируемого BuilerWorker а так же от IRankerProvider
Но вы не решили проблему, с которой я начал — как в ранжировщики передавать «опциональные» параметры.
Это оправдано по производительности, т.к. разрешение зависимостей делается единожды, а параметры передаются для каждой уникальной пары из ранжировщика и команды.
Это оправдано архитектурно, т.к. компоненты использующие DD могут использовать друг друга, а, следовательно, ранжировщики смогут получить доступ не только к данным, зарегистрированным в текушем контексте, но и к данным зарегистрированным во внешнем контексте по отношению к TopBuilder.
Да, при кривой конфигурации в самом деле нет никакого выигрыша. Но в этом случае думать в первую очередь надо о том, что в проекте ещё кривое, кроме конфигурации. (Тот факт, что выигрыша не будет, если кто-то где-то ошибется не означает что его нет совсем и быть не может.)
Если доступа ко внешним данным никому не нужно, то я не рекомендую применять описаный шаблон. Даже запрещаю это делать.
Если же всё-таки он нужен, то компонент который инжектирует данные должен быть соответствующем образом отмечен, как и компонент, реализация которого допускает импорт данных из контейнера c явным указанием всех таких типов данных. Например, аттрибутами.
Есть ещё маркерные интерфейсы.
А сделать это очень просто…
BuildTop
. Применяя шаблон Data Dependency мы позволяем любой реализации ранжировщика получить доступ к этим данным, но не обязываем её это делать.В случае, когда никому из ранжировщиков эти данные не нужны — Data Dependency применять не нужно.
Шаблон полезно иметь в арсенале на случай, если такое требование появится позже. В этом случае мы просто применим рефакторинг «Convert method to Method Object» и шаблон Data Dependency. Изменения интерфейса
IRanker
не потребуется. Таким образом, мы удовлетворим новое требование и сохраним совместимость с имеющимися реализациями.«Композиция» реализовывала другой интерфейс, ибо результат подсчета композитного рейтинга не был целым числом. (В моем случае вообще не был числом).
Упомянутая возможность Unity мне хорошо известна и была использована в первую очередь. Проблема может возникнуть, если оценщики зависят друг от друга, именованые регистрации в Unity, к сожалению, друг о друге ничего не знают. Дефолтная реализация
IRankerProvider
делает именно то, что вы написали — разрешает массив. Но, сам интерфейс делается для того, чтобы поведеление можно было изменить. Можно ещё зарегистрировать InjectionFactory для массива. Как говорится, по желанию и никакого приведения типов.BuilerWorker
в даной ситуации больше похож на паттерн «MethodObject» и ничто не мешает его тестировать, при соответствующем изменении видимости.Но вы не решили проблему, с которой я начал — как в ранжировщики передавать «опциональные» параметры.
Это оправдано архитектурно, т.к. компоненты использующие DD могут использовать друг друга, а, следовательно, ранжировщики смогут получить доступ не только к данным, зарегистрированным в текушем контексте, но и к данным зарегистрированным во внешнем контексте по отношению к TopBuilder.