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