Главная страница   /   3.4. Перспектива DI-контейнеров (Внедрение зависимостей в .NET

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

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

Марк Симан

3.4. Перспектива DI-контейнеров

Теперь, когда я описал, что такое DI-контейнер и как применить его в Composition Root, я хочу слегка сменить темп и предоставить вам обзор текущего состояния DI-контейнеров в .NET экосистеме. Это такие самые устойчивые аспекты DI-контейнеров, как историческое происхождение, и то, почему доступно так много контейнеров с открытым исходным кодом.

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

Выбор DI-контейнера

Решение использовать механизм внедрения зависимостей в качестве технологии не должно зависеть от выбора конкретного DI-контейнера. Механизм внедрения зависимостей в первую очередь является технологией, и я буду использовать Poor man's DI на протяжении почти всех частей "Каталог DI" и "DI самостоятельно" для того, чтобы подчеркнуть этот вопрос.

Однако DI-контейнер упростит вашу жизнь, поэтому используйте его там, где только можете. Если использовать контейнеры согласно выделенным в этой книге паттернам, то можно столкнуться с несколькими недостатками, но нужно рассмотреть еще кое-что.

Процесс принятия решения

DI-контейнер – это стабильная зависимость, поэтому с точки зрения DI использование DI-контейнера не является проблемой, но существуют другие, второстепенные проблемы, которые нужно рассмотреть:

  • Добавление другой библиотеки всегда добавляет некоторую сложность в приложение – не в терминах удобства сопровождения, а в терминах кривой обучения. Новым разработчикам нужно будет не только понять код приложения, но также понять API выбранного DI-контейнера. Надеюсь, что в этой главе я сумел дать вам понять, что с помощью изолированного использования контейнера в Composition Root вы сможете защитить контейнер от начинающих разработчиков. Если вы используете механизм автоматической регистрации, то контейнер может даже взять на себя заботу об инфраструктуре, не привлекая при этом к себе внимание.
  • За исключением платформы Managed Extensibility Framework (MEF), вам нужно разворачивать сборки DI-контейнера вместе со своим приложением. Это могло бы потенциально иметь легальные последствия, хотя это и не правдоподобно. Все универсальные DI-контейнеры с открытым исходным кодом имеют разрешающие лицензии, но я не судья, поэтому не делайте ставку на мои слова: проконсультируйтесь со своим собственным консультантом.
  • И еще раз за исключением MEF все остальные DI-контейнеры являются библиотеками с открытым исходным кодом. Для каждого из этих контейнеров вам приходится оценивать, насколько вы доверяете людям или организации, создавшим эти контейнеры.
  • Существуют технические различия между различными DI-контейнерами. Во введении к части "DI-контейнеры" я предоставил вам таблицу, в которой перечисляются преимущества и недостатки каждого контейнера, рассматриваемого в этой книге. Вы можете использовать эту таблицу как стартовую точку, а потом чтение глав о каждом из контейнеров станет для вас интересным.

Выбор DI-контейнера не должен быть сложным. Возьмите один для раскрутки, а потом посмотрите, подходит ли он вашим нуждам – если не подходит, то замените его другим. Когда вы заключите DI-контейнер в Composition Root, вы сможете заменять контейнеры относительно свободно.

Выбранные DI-контейнеры

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

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

В таблице 3-4 перечисляются DI-контейнеры, рассматриваемые в части "DI-контейнеры". Выбор основывается на таких критериях, как релевантность, доля на рынке, характерные черты, но этот список является субъективным и неокончательным. Несколько популярных контейнеров (например, Ninject) не включены в этот список, главным образом, из-за ограничений во времени и пространстве.

Таблица 3-4: Выбранные DI-контейнеры. Доступно больше контейнеров, но эти выбраны либо потому что они широко используются, либо они представляют собой интересный аспект DI или потому что они станут важными в будущем
Название Организация Комментарии
Castle Windsor Open Source Состоявшийся и широко используемый
StructureMap Open Source Состоявшийся и широко используемый
Spring.NET SpringSource Состоявшийся и широко используемый порт Java Spring DI-контейнера
Autofac Open Source Наиболее современный DI-контейнер, созданный на основании характеристик языка C# 3.0
Unity Microsoft patterns&practices Первая роль компании Microsoft в пространстве DI, но не продукт по существу
Managed Extensibility Framework (MEF) Microsoft Поставляется вместе с .NET 4, но в действительности не является DI-контейнером

Часть "DI-контейнеры" посвящена этим DI-контейнерам, причем для каждого из них выделена отдельная глава.

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

Microsoft и DI

Несмотря на то, что платформа .NET является продуктом компании Microsoft, другие организации (часто отдельные лица) становятся более известными, когда дело доходит до механизма внедрения зависимостей в .NET. Вкратце это может относиться к тому факту, что компания Microsoft не предлагает ни одного DI-контейнера в стандартной библиотеке классов (BCL). Хотя как предложение единственным DI-контейнером компании Microsoft является появившийся относительно недавно Unity.

Думаю, справедливо будет сказать, что за множество первых лет жизни .NET Framework компания Microsoft блаженно игнорировала любую сущность DI. Не просто точно объяснить, почему так происходило, и я сомневаюсь, что это когда-либо было явной стратегией.

Краткая история DI в .NET

Ниже приведена моя субъективная попытка сделать обзор истории DI в .NET для того, чтобы объяснить, почему компания Microsoft столь долго игнорировала механизм внедрения зависимостей (см. рисунок 3-14). Насколько я осведомлен, на этот вопрос нет авторитетного ответа.

Рисунок 3-14: Временные рамки релизов выбранных платформ и DI-контейнеров. Обратите внимание на то, насколько состоявшейся оказалась Java в 2004 году по сравнению с .NET.

Кажется, что до того, как попасть в .NET, DI выросла из сообщества Java с открытым исходным кодом. Мартин Фаулер опубликовал свою статью о DI в начале 2004 года в качестве реакции на непрерывную работу. В это время текущей версией .NET была версия 1.1, и компания Microsoft работала над версией .NET 2.0, в то время как Java быстрыми темпами достигала своего десятилетия. Я верю, что компания Microsoft в то время просто направила свои усилия в другом направлении. Даже если бы они в то время были хорошо осведомлены насчет DI, думаю, для них все равно были бы приоритетны другие возможности, например, дженерики.

В июне 2004 года был выпущен DI-контейнер StructureMap, обогнав Castle Windsor всего на полгода.

В конце 2005 года компания Microsoft выпустила .NET 2.0, главной новой возможностью которой стали дженерики, а затем Microsoft решила сфокусироваться на WCF, WPF, а позднее LINQ для своего следующего крупного релиза (Visual Studio 2008).

Тем временем DI медленно приобретал популярность. В 2006 году появился Spring.NET.

В начале 2008 Microsoft patterns&practices выпустили Unity, которая для большинства последователей школы Microsoft казалась приближением к DI. Этот четырехгодовалый промежуток времени дал опытным личностям хороший старт, а популярность DI-контейнеров, подобных StructureMap и Castle Windsor, возросла.

Основа DI

Интересным наблюдением из рисунка 3-14 является то, как быстро члены сообщества .NET разработчиков подхватили идею DI. Согласно домашней странице Castle Windsor понятия зарождались даже до статьи Фаулера:

Castle вырос из проекта Apache Avalon в середине 2003 года в виде попытки создания самой простой инверсии управления контейнером.

Веб-страничка Castle от 01.08.2008

На протяжении длительного времени для .NET DI-контейнеры оставались источником движения, а многие ведущие члены симпатизировали разработке Agile. В действительности даже если архитектура модульного приложения имеет множество различных преимуществ, все равно кажется, что в первую очередь именно вопрос тестируемости мотивировал людей на разработку и использование DI-контейнеров (что также является справедливым и в моем случае).

В это время официальной методологией разработки в компании Microsoft была Microsoft Solutions Framework (MSF) 3.0 – каскадный процесс, который оставляет небольшое пространство для таких приемов разработки Agile, как разработка через тестирование (TDD). Короче говоря, это было совершенно другим образом мышления.

С течением времени разработка Agile, TDD и DI доказали свою эффективность и приобрели популярность, а Microsoft, казалось, также медленно продвигалась к поддержке этого стиля. В противоположность ситуации 2004 года команды разработки теперь открыто обсуждают DI, TDD и другие вопросы, относящиеся к разработке Agile.

DI-контейнеры компании Microsoft

С течением времени команда patterns&practices компании Microsoft разработала множество корректур для различных областей, относящихся к .NET. Большая часть опыта, приобретенного из этих проектов, использовалась для определения рамок дальнейшей разработки самого .NET Framework. В качестве примера Updater Application Block предоставил богатый опыт, который в дальнейшем использовался при разработке ClickOnce.

В начале 2008 года команда patterns&practices выпустила свою первую Community Technical Preview (CTP) (небольшая ознакомительная версия) версию Unity, их новый DI-контейнер, а в апреле 2008 года вышел релиз 1.0. Unity – это развитый DI-контейнер, который поддерживает композицию объектов, механизм управления жизненным циклом и механизм перехвата. Это не продукт компании Microsoft, но скорее проект с открытым исходным кодом, который возможно разработан Microsoft.

Object Builder

Кажется, существует некоторая путаница в вопросе о том, когда точно patterns&practices представили миру DI-контейнер. При введении в начале 2006 года Enterprise Library для .NET 2.0 команды patterns&practices она содержала модуль с названием Object Builder, который использовался для создания сложных объектов из составных элементов.

Она была атрибутно-управляемой и работала только для классов, которые были сильно интегрированы с самим Object Builder. Его никогда не представляли как DI-контейнер, хотя было общепризнано, что на его основе можно было бы создать DI-контейнер.

Многие люди ошибочно верят, что Object Builder был первым DI-контейнером компании Microsoft, но это не правда: этот титул получил Unity.

Вместе с .NET 4.0 компания Microsoft предоставила Managed Extensibility Framework (MEF), который отмечает, что к первым DI сущностям явно обращались в рамках самой .NET. При первом выпуске MEF не был полноценным контейнером, который поддерживал все три аспекта DI, но скорее был движком, который фокусировался на композиции объектов.

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