DI анти-паттерны
В гастрономическом плане Дания была одной из развивающихся стран в 1970х: я был там, но я никогда не страдал, потому что не знал ничего лучшего. В основном использовались мясо и картофель, но постепенно приходили и зарубежные идеи. Я думаю, что одна из причин заключалась в том, что это было на заре эры массового туризма.
Датчане массово отправлялись на юг, в другие части Европы, и самые смелые пробовали местную еду. После возвращения домой более молодое поколение все больше готовило пасту, но ни один итальянец не распознал бы датскую версию соуса болоньезе.
Вот, что я думаю, произошло. Какому-то предприимчивому датскому туристу понравилась тальятелла алла болоньезе (tagliatelle alla bolognese) так сильно, что она решила попытаться приготовить ее, когда вернулась домой. (Я предполагаю, что это была женщина, потому что мужчины в то время много не готовили). Она сделала все, чтобы вспомнить, что входит в соус, но это было не так просто из-за долгой поездки на автобусе обратно в Данию.
Что касается ингредиентов, грудинка и красное вино были забыты, прежде чем она покинула Италию, мясной бульон и куриная печень были потеряны из памяти где-то в Австрии или Швейцарии, а овощи один за другим выпадали из головы во время долгого пути через (Западную) Германию. Когда она пересекла датскую границу, все, что осталось от оригинального рецепта, – это нарезанный лук и мясной фарш, и их подают только с одним типом пасты, которая легко доступна в Дании в то время - спагетти.
Мы ели блюдо, которое получилось в результате, в течение многих лет и любили его. В какой-то момент в 1980-х годах, в рецепт были добавлены томатная паста и орегано, чтобы сделать его более похожим на исходный. Это был рецепт, который я использовал более чем десять лет, пока кто-то не подсказал мне, что для улучшения вкусовых качеств можно добавить еще морковь, сельдерей, куриную печень, красное вино и так далее.
Смысл истории заключается в том, что я думал, что делаю рагу алла болоньезе (ragù alla bolognese), тогда как в действительности я не был даже близок к этому. Мне никогда не приходило в голову ставить под сомнение подлинность рецепта, потому что я вырос с ним. Хотя подлинность не является конечным критерием, блюдо, приготовленное по подлинному рецепту, намного вкуснее, и я не собираюсь возвращаться к моему старому рецепту.
В предыдущей главе я кратко сравнил паттерны проектирования с рецептами. Паттерн обеспечивает общий язык, который мы можем использовать, чтобы сжато обсудить сложное понятие, и рагу алла болоньезе – это такое понятие, потому что мы можем обсудить, как оно согласуется с тальятелле или лазаньей. С другой стороны, когда понятие (или, скорее, реализация) искривлено, мы получаем анти-паттерн.
Примечание
Анти-паттерн представляет собой описание часто встречающихся решений проблемы, которые несомненно приводят к негативным последствиям (William J. Brown et al., AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis (New York: Wiley Computer Publishing), 1998, 7).
Анти-паттерны часто бывают вызваны незнанием (как с моим соусом болоньезе), и их нужно избегать, а знание этих общих ловушек может помочь вам избежать их. Они являются более или менее формализованным способом описания распространенных ошибок, которые люди совершают снова и снова, независимо друг от друга.
В этой главе я опишу некоторые общие анти-паттерны, связанные с DI. За время моей карьеры я видел, как все они используются в той или иной форме, и, каюсь, я сам применял более чем один из них. Во многих случаях они казались искренними попытками применить DI в приложении, но без полного понимания основ DI, реализация приносила больше вреда, чем пользы.
Изучение этих анти-паттернов должно дать вам представление о том, каких ловушек нужно избегать в ваших первых DI проектах. Ваши ошибки не будут выглядеть точно так же, как мои или примеры, представленные здесь, но эта глава покажет вам, где кроются опасные признаки.
Анти-паттерны могут быть исправлены путем рефакторинга кода к одному из DI паттернов, приведенных в главе 4. Сложность исправления в каждом отдельном случае зависит от деталей реализации, но для каждого анти-паттерна я предоставлю некоторые обобщенные рекомендации, как провести рефакторинг по направлению к паттерну.
Совет
В этой главе я не уделяю слишком много места рефакторингу от DI анти-паттерна к DI паттерну, потому что это не главная тема этой книги. Если вы заинтересованы в получении дополнительной информации о том, как вы можете переместить существующее приложение в направлении DI, есть целая книга, где обсуждается рефакторинг таких приложений: Working Effectively with Legacy Code (Michael Feathers, Working Effectively with Legacy Code (New York: Prentice Hall, 2004)). Хотя в ней не рассматривается исключительно DI, она охватывает многие из тех же понятий, что и я в данной книге.
Анти-паттерны, описанные в этой главе, приведены в таблице 5-1. Рисунок 5-1 иллюстрирует структуру главы.
Таблица 5-1: DI анти-паттерны
Анти-паттерн | Описание |
Control Freak | Зависимости управляются напрямую, в отличие от инверсии управления (Inversion of Control, IoC). |
Bastard Injection | Foreign Default используются как значения по умолчанию для зависимостей. |
Constrained Construction | Предполагается, что конструкторы имеют особенную, индивидуальную сигнатуру. |
Service Locator | Неявный сервис может подавать зависимости потребителю, но нет гарантии, что он это сделает. |
Рисунок 5-1: Структура этой главы принимает форму каталога анти-паттернов. Каждый анти-паттерн описан так, что вы можете прочитать о нем отдельно от других анти-паттернов.

Внимание
Эта глава отличается от других глав, потому что большая часть кода, который я покажу вам, дает примеры того, как не реализовывать DI. Не пытайтесь повторить это дома!
Так же, как внедрение в конструктор является наиболее важным DI паттерном, Control Freak является самым доминирующим анти-паттерном. Он всеми силами предотвращает вас от применения любого надлежащего и нужного внедрения зависимостей, так что вам придется сосредоточить свою энергию на этом анти-паттерне, прежде чем заняться другими. С другой стороны, наиболее опасным является Service Locator, потому что создается впечатление, что он на самом деле решает проблему.
Остальная часть этой главы описывает каждый анти-паттерн более подробно. Вы можете прочитать ее от начала до конца или только о том, в чем вы заинтересованы: каждый анти-паттерн занимает отдельный раздел. Тем не менее, если вы решили прочитать только об одном анти-паттерне, вы должны сосредоточить свое внимание на Control Freak.