Может ли кто-нибудь объяснить мне, как использовать контейнеры МОК?
Я интенсивно использую инъекцию зависимостей через параметры и конструкторы. Я понимаю принцип в этой степени и доволен этим. По моим крупным проектам у меня заканчивается слишком много зависимостей, которые вводятся (все, что попадает в двойные фигуры, кажется большим - мне нравится термин "код макарон" ).
Таким образом, я рассматриваю контейнеры МОК. Я прочитал несколько статей по ним, и до сих пор я не видел выгоды. Я могу видеть, как он помогает в отправке групп связанных объектов или в получении одного и того же типа снова и снова. Я не уверен, как они помогут мне в моих проектах, где у меня может быть более ста классов, реализующих один и тот же интерфейс, и где я использую их все в разных порядках.
Итак, может ли кто-нибудь указать мне на некоторые хорошие статьи, которые не только описывают концепции контейнеров МОК (желательно, не раздувая их в частности), но и подробно показывают, как они приносят мне пользу в этом типе проекта и как они вписываются в масштаб большой архитектуры?
Я бы хотел увидеть некоторые неязычные специфические вещи, но при необходимости мой предпочтительный язык - С#.
Ответы
Ответ 1
Инверсия управления в первую очередь касается управления зависимостями и обеспечения проверяемого кода. Из классического подхода, если у класса есть зависимость, естественная тенденция состоит в том, чтобы дать классу, который имеет прямой контроль зависимости от управления его зависимостями. Обычно это означает, что класс, который имеет зависимость, будет "обновлять" свои зависимости внутри конструктора или по требованию в его методах.
Инверсия управления - это просто... он инвертирует то, что создает зависимости, экстернализирует этот процесс и вводит их в класс, который имеет зависимость. Обычно объект, создающий зависимости, мы называем контейнером IoC, который отвечает за не только создание и вложение зависимостей, но и управление их сроками службы, определение их образа жизни (подробнее об этом за секунду), а также предложение разнообразных других возможностей. (Это основано на Castle MicroKernel/Windsor, который является моим контейнером IoC по выбору... его надежным письменным, очень функциональным и расширяемым. Существуют другие контейнеры IoC, которые проще, если у вас более простые потребности, такие как Ninject, Microsoft Unity и Spring.NET.)
Учтите, что у вас есть внутреннее приложение, которое можно использовать либо в локальном контексте, либо в удаленном контексте. В зависимости от некоторых обнаружимых факторов вашему приложению может потребоваться загрузить "локальные" реализации ваших услуг, а в других случаях может потребоваться загрузить "remote" реализации ваших услуг. Если вы придерживаетесь классического подхода и создаете свои зависимости непосредственно в классе, который имеет эти зависимости, то этот класс будет вынужден разбить два очень важных правила о разработке программного обеспечения: Разделение проблем и единая ответственность. Вы пересекаете границы беспокойства, потому что ваш класс теперь обеспокоен как своей внутренней целью, так и проблемой определения того, какие зависимости он должен создать и как. Класс также теперь несет ответственность за многие вещи, а не за одну вещь, и имеет множество причин для изменения: изменения его внутренних целей, процесс создания изменений его зависимостей, способы обнаружения изменений удаленных зависимостей, какие зависимости могут потребоваться для его зависимостей, и т.д.
Инвертируя управление зависимостями, вы можете улучшить свою архитектуру системы и поддерживать SoC и SR (или, возможно, достичь этого, когда вы ранее не могли из-за зависимостей.) Поскольку внешний объект, контейнер IoC, теперь контролирует, как ваши зависимости создаются и вводятся, вы также можете получить дополнительные возможности. Контейнер может управлять жизненными циклами ваших зависимостей, создавая и уничтожая их более гибкими способами, которые могут повысить эффективность. Вы также получаете возможность управлять стилями жизни ваших объектов. Если у вас есть тип зависимостей, которые создаются, используются и возвращаются на очень частой основе, но которые имеют мало или вообще не имеют состояния (скажем, заводов), вы можете дать им объединенный образ жизни, который скажет, что контейнер автоматически создается пул объектов для этого конкретного типа зависимостей. Существует много образа жизни, и такой контейнер, как Castle Windsor, обычно дает вам возможность создавать свои собственные.
Лучшие контейнеры IoC, такие как Castle Windsor, также обеспечивают большую расширяемость. По умолчанию Windsor позволяет создавать экземпляры локальных типов. Возможно создание средств, которые расширяют возможности создания типа Windsor для динамического создания прокси-серверов веб-служб и хостов WCF-сервиса "на лету" во время выполнения, что исключает необходимость их создания вручную или статически с помощью таких инструментов, как svcutil (это то, что я сделал сам недавно.) Существует множество возможностей для поддержки IoC существующих инфраструктур, таких как NHibernate, ActiveRecord и т.д.
Наконец, IoC обеспечивает стиль кодирования, который обеспечивает единый тестируемый код. Одним из ключевых факторов при тестировании блока кода является экстернализация управления зависимостями. Без возможности предоставления альтернативных (издевающихся, закодированных и т.д.) Зависимостей тестирование одиночной "единицы" кода в изоляции является очень сложной задачей, оставив интеграционное тестирование единственным альтернативным стилем автоматизированного тестирования. Поскольку IoC требует, чтобы ваши классы принимали зависимости через инъекцию (по конструктору, свойству или методу), каждый класс обычно, если не всегда, сводится к одной ответственности должным образом разобщенной озабоченности и полностью макетируемых зависимостей.
IoC = лучшая архитектура, большая сплоченность, улучшенное разделение проблем, классы, которые легче свести к одной ответственности, легко настраиваемые и взаимозаменяемые зависимости (часто без необходимости перекомпиляции вашего кода), гибкие стили жизни зависимостей и время жизни управления и единичного тестируемого кода. IoC - это своего рода образ жизни... философия, подход к решению общих проблем и решение важнейших передовых методов, таких как SoC и SR.
Даже (точнее, особенно) с сотнями различных реализаций одного интерфейса, IoC может многое предложить. Может потребоваться некоторое время, чтобы ваша голова была полностью обернута вокруг него, но как только вы полностью поймете, что такое IoC и что он может сделать для вас, вы никогда не захотите делать какие-либо другие действия (за исключением, возможно, разработки встроенных систем... )
Ответ 2
Если у вас более сотни классов, реализующих общий интерфейс, IoC не очень поможет, вам понадобится factory.
Таким образом, вы можете сделать следующее:
public interface IMyInterface{
//...
}
public class Factory{
public static IMyInterface GetObject(string param){
// param is a parameter that will help the Factory decide what object to return
// (that is only an example, there may not be any parameter at all)
}
}
//...
// You do not depend on a particular implementation here
IMyInterface obj = Factory.GetObject("some param");
Внутри factory вы можете использовать контейнер IoC для извлечения объектов, если хотите, но вам нужно будет зарегистрировать каждый из классов, реализующих данный интерфейс, и связать их с некоторыми ключами (и использовать их ключи как параметры в методе GetObject()).
IoC особенно полезен, когда вы должны извлекать объекты, которые реализуют разные интерфейсы:
IMyInteface myObject = Container.GetObject<IMyInterface>();
IMyOtherInterface myOtherObject Container.GetObject<IMyOtherInterface>();
ISomeOtherInterface someOtherObject = Container.GetObject<ISomeOtherInterface>();
См? Только один объект, чтобы получить несколько разных объектов типа и никаких ключей (самими ключами являются сами по себе). Если вам нужен объект для получения нескольких разных объектов, но при реализации одного и того же интерфейса IoC вам не поможет.
Ответ 3
В последние несколько недель я сделал резкий переход от инъекции зависимостей только к полной инверсии управления с помощью Castle, поэтому я понимаю, откуда ваш вопрос.
Некоторые причины, по которым я не хочу использовать контейнер IOC:
-
Это небольшой проект, который не будет расти так сильно. Если между конструкторами и вызовами этих конструкторов существует соотношение 1:1, использование контейнера IOC не приведет к сокращению количества кода, который я должен написать. Вы не нарушаете "не повторяйте себя", пока не обнаружите, что копируете и вставляете то же самое "var myObject = new MyClass (someInjectedDependency)" во второй раз.
-
Мне, возможно, придется адаптировать существующий код, чтобы облегчить загрузку в контейнеры IOC. Это, вероятно, не обязательно, пока вы не освоите некоторые более крутые функции, ориентированные на аспекты Aspect, но если вы забыли сделать метод виртуальным, опечатали этот класс методов и не реализовали интерфейс, неудобно вносить эти изменения из-за существующих зависимостей, а затем сделать переключатель не совсем привлекательным.
-
Он добавляет дополнительную внешнюю зависимость к моему проекту - и моей команде. Я могу убедить остальную часть моей команды, что структурирование их кода, чтобы позволить DI раздуваться, но я в настоящее время единственный, кто знает, как работать с Castle. На небольших, менее сложных проектах это не будет проблемой. Для более крупных проектов (которые, как это ни парадоксально, будут извлекать наибольшую выгоду из контейнеров МОК), если я не смогу евангелизировать использование контейнера МОК достаточно хорошо, переход от меня к моей команде никому не поможет.
/li >
Некоторые из причин, почему я не хочу возвращаться к простому DI:
Например, отсутствует зависимость с Замком:
"Невозможно создать компонент MyClass как у него есть зависимости, которые нужно выполнить. Служба ожидает следующего зависимостей:
Услуги: - IMyService, который не был зарегистрирован.
Отсутствие зависимости без замка:
Ссылка на объект не установлена на экземпляр объекта
Dead Last: возможность обмена инъецированными службами во время выполнения, путем редактирования Xml файла. Мое мнение таково, что это самая тугая особенность, но я вижу, что это просто обледенение на торте. Я предпочел бы подключить все свои услуги в коде, но я уверен, что в будущем буду сталкиваться с головной болью, когда мой ум будет изменен.
Я признаю, что, будучи новичком в МОК и Замке, я, вероятно, только царапаю поверхность, но до сих пор я искренне люблю то, что вижу. Я чувствую, что последние несколько проектов, которые я построил с ними, действительно способны реагировать на непредсказуемые изменения, которые возникают изо дня в день в моей компании, чувство, которое я никогда не испытывал раньше.
Ответ 4
У меня нет ссылок, но вы можете предоставить вам пример:
У вас есть веб-контроллер, которому необходимо вызвать службу с уровнем доступа к данным.
Теперь, я беру его в свой код, вы создаете эти объекты самостоятельно во время компиляции. Вы используете достойный шаблон дизайна, но если вам когда-либо понадобится изменить реализацию, скажем, дао, вам нужно войти в код и удалить код, который устанавливает эту зависимость, перекомпилировать/протестировать/развернуть. Но если вы собираетесь использовать контейнер IOC, вы просто измените класс в конфигурации и перезапустите приложение.
Ответ 5
Попробуйте следующее:
Ответ 6
Джереми Фрей пропустил одну из самых больших причин для использования контейнера IOC: он делает ваш код более легким для макета и тестирования.
Поощрение использования интерфейсов имеет множество других приятных преимуществ: лучшее распределение, проще динамически создавать прокси-серверы для таких вещей, как декларативные транзакции, аспектно-ориентированное программирование и удаленное взаимодействие.
Если вы считаете, что IOC подходит только для замены вызовов на "новый", вы не получите его.
Ответ 7
Контейнеры IoC обычно выполняют инъекции зависимостей, которые в некоторых проектах не имеют большого значения, но некоторые из фреймворков, которые предоставляют контейнеры IoC, предлагают другие услуги, которые делают его целесообразным использовать.
Например, замок имеет полный список услуг, помимо контейнера IoC. Некоторые из них - динамические прокси, управление транзакциями и объекты NHibernate.
Тогда я думаю, вы должны рассмотреть IoC contianers как часть рамок приложения.
Вот почему я использую контейнер IoC:
1.Инструменты для записи будут проще. На самом деле вы пишете разные конфигурации, чтобы делать разные вещи
2. Добавление разных плагинов для разных сценариев (например, для разных клиентов)
3.Интерирование классов для добавления различных аспектов в наш код.
4. Поскольку мы используем NHibernate, Управление транзакциями и NHibernate Facilites of Castle очень помогают в разработке и обслуживании нашего кода.
Он, как и все технические аспекты нашего приложения, обрабатывается с использованием рамок приложения, и у нас есть время подумать о том, чего действительно хотят клиенты.