Я уверен, что по этому вопросу можно многое сказать, и, надеюсь, я отредактирую этот ответ, чтобы добавить больше позже (и, надеюсь, больше людей добавят больше ответов и идей), но лишь пара быстрых замечаний к вашему сообщение ...
Использование контейнера IoC - это подмножество инверсии управления , а не все. Вы можете использовать инверсию управления как конструктивную конструкцию, не полагаясь на структуру контейнера IoC. В самом простом случае инверсию управления можно сформулировать в этом контексте как «поставь, а не создавай». Пока ваши объекты внутренне не зависят от реализаций других объектов, а вместо этого требуют, чтобы им были предоставлены реализованные реализации, то вы используете инверсию управления. Даже если вы не используете инфраструктуру контейнера IoC.
Что касается программирования на интерфейс ... Я не уверен, каким был ваш опыт работы с контейнерами IoC (мой личный фаворит StructureMap ), но вы определенно программируете на интерфейс с IoC , Идея, по крайней мере, в том, как я это использовал, заключается в том, что вы отделяете свои интерфейсы (ваши типы) от ваших реализаций (ваших внедренных классов). Код, который опирается на интерфейсы, запрограммирован только для них, и реализации этих интерфейсов внедряются при необходимости.
Например, у вас может быть IFooRepository
, который возвращает из экземпляров хранилища данных типа Foo
. Весь ваш код, которому нужны эти экземпляры, получает их из предоставленного объекта типа IFooRepository
. В другом месте вы создаете реализацию FooRepository
и конфигурируете свой IoC для обеспечения того, чтобы везде требовался IFooRepository
. Эта реализация может получить их из базы данных, из файла XML, из внешней службы и т. Д. Не имеет значения, где. Этот контроль был инвертирован. Ваш код, который использует объекты типа Foo
, не заботится о том, откуда они берутся.
Очевидное преимущество заключается в том, что вы можете поменять эту реализацию в любое время. Вы можете заменить его тестовой версией, изменить версии в зависимости от среды и т. Д. Но имейте в виду, что вам также не нужно иметь такое соотношение интерфейсов 1: 1 к реализациям в любой момент времени.
Например, я однажды использовал инструмент генерации кода на предыдущем задании, который выплевывал тонны и тонны кода DAL в один класс. Разбить его на части было бы больно, но не так уж и сложно было настроить его так, чтобы он выкладывался в конкретные имена методов / свойств. Поэтому я написал несколько интерфейсов для своих репозиториев и сгенерировал один класс, который реализовал всех из них. Для этого сгенерированного класса это было ужасно. Но остальному моему приложению было все равно, потому что оно рассматривало каждый интерфейс как свой собственный тип. Контейнер IoC только что предоставил один и тот же класс для каждого.
Мы смогли быстро приступить к работе, и никто не ждал разработки DAL. В то время как мы продолжали работать в коде домена, который использовал интерфейсы, младшему разработчику было поручено создавать лучшие реализации. Те реализации были позже заменены, все было хорошо.
Как я уже упоминал ранее, все это может быть достигнуто без контейнера IoC. На самом деле важен сам шаблон.