Это похоже на голосование без ответа, но я хочу обдумать вслух - возможно, другие тоже видят вещи таким образом.
Классическая ОО использует конструкторы для определения публичного контракта «инициализации» для потребителей класса (скрытие ВСЕХ деталей реализации; так называемая инкапсуляция). Этот контракт может гарантировать, что после создания экземпляра у вас есть готовый к использованию объект (т. Е. Дополнительные шаги инициализации, которые пользователь должен запомнить (т. Е. Забыть)).
(конструктор) DI, несомненно, нарушает инкапсуляцию, пропуская подробности реализации через этот открытый интерфейс конструктора. Пока мы все еще считаем, что открытый конструктор отвечает за определение договора инициализации для пользователей, мы создали ужасное нарушение инкапсуляции.
Теоретический пример:
Класс Foo имеет 4 метода и ему требуется целое число для инициализации, поэтому его конструктор выглядит как Foo (int size) , и он сразу становится понятным пользователям класса Foo что они должны предоставить размер при создании экземпляра, чтобы Foo работал.
Допустим, этой конкретной реализации Foo также может потребоваться IWidget , чтобы выполнить свою работу. Внедрение в конструктор этой зависимости заставило бы нас создать конструктор, подобный Foo (int size, IWidget widget)
Что меня раздражает в этом, так это теперь у нас есть конструктор, который смешивает данные инициализации с зависимостями - один вход представляет интерес для пользователя класса ( size ), другой является внутренней зависимостью, которая только вводит пользователя в заблуждение и является подробностью реализации ( widget ).
Параметр размера НЕ является зависимостью - это просто значение инициализации для каждого экземпляра. IoC удобен для внешних зависимостей (например, виджетов), но не для внутренней инициализации состояния.
Еще хуже, что если виджет необходим только для 2 из 4 методов этого класса; У меня могут быть накладные расходы на инстанцирование для Widget, даже если он не используется!
Как скомпрометировать / примирить это?
Одним из подходов является переключение исключительно на интерфейсы для определения контракта на эксплуатацию; и отменить использование конструкторов пользователями.
Чтобы быть согласованными, все объекты должны были бы быть доступны только через интерфейсы и создаваться только через некую форму распознавателя (например, контейнер IOC / DI). Только контейнер получает возможность создавать вещи.
Это касается зависимости Widget, но как нам инициализировать «размер», не прибегая к отдельному методу инициализации в интерфейсе Foo? Используя это решение, мы утратили способность гарантировать, что экземпляр Foo будет полностью инициализирован к моменту его получения. Облом, потому что мне действительно нравится идея и простота внедрения конструктора.
Как мне добиться гарантированной инициализации в этом мире DI, когда инициализация БОЛЬШЕ, чем ТОЛЬКО внешние зависимости?