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