Главная страница   /   6.6. Резюме (Внедрение зависимостей в .NET

Внедрение зависимостей в .NET

Внедрение зависимостей в .NET

Марк Симан

6.6. Резюме

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

Один из самых универсальных и полезных шаблонов проектирования, связанных с DI, является абстрактная фабрика. Мы можем использовать ее для перевода простых значений времени выполнения, таких как строки или числа, введенных пользователями, в экземпляры сложных абстракций. Мы также можем использовать абстрактные фабрики в сочетании с интерфейсом IDisposable, чтобы имитировать краткосрочные зависимости, такие как соединения с внешними ресурсами.

Совет

Переводите значения времени выполнения в зависимости при помощи абстрактных фабрик.

Совет

Имитируйте соединения при помощи абстрактных фабрик, которые создают одноразовые зависимости.

Проблема, которая иногда возникает, – это циклы зависимостей. Они, как правило, появляются из-за того, что API-интерфейсы являются слишком строгими. Чем больше API строится вокруг парадигмы запросов, тем больше шансов получить циклы. Мы можем избежать циклов, соблюдая Принцип Голливуда (Hollywood Principle). Методы с void сигнатурами могут быть преобразованы в события, которые часто могут быть использованы для прерывания циклов. Если перепроектирование невозможно, мы можем разорвать цикл, изменив одно внедрение в конструктор во внедрение в свойство. Тем не менее, это надо делать аккуратно, потому что это меняет семантику потребителя.

Совет

Ломайте циклы при помощи внедрения в свойство.

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

Совет

Решайте проблему Constructor Over-injection путем рефакторинга к фасадным сервисам.

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

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

Если мы напишем много юнит тестов (в частности, если мы используем Test-Driven Development), тесная связанность быстро проявит себя в сложном и хрупком тестовом коде. Или, вероятно, потому что это невозможно – провести модульное тестирование больших частей приложения.

Совет

Пишите автоматизированные тесты для обеспечения слабой связанности.

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

В этой главе описаны решения для часто встречающихся проблем с DI. Вместе с двумя предыдущими главами она образует каталог паттернов, анти-паттернов и рефакторинга. Данный каталог представляет собой часть 2 книги. В части 3 мы повернемся лицом к трем измерениям DI: Композиции объектов (Object Composition), Управлению жизненным циклом (Lifetime Management) и Перехвату (Interception).