В любом месте, где вам нужно значение времени выполнения для построения определенной зависимости, абстрактная фабрика является решением.
Я бы поспорил с этим.Зависимости не должны создаваться с использованием данных времени выполнения, как объяснено здесь .Таким образом, в статье говорится:
Не вставляйте данные времени выполнения в компоненты приложения во время построения;это вызывает двусмысленность, усложняет корень композиции с дополнительной ответственностью и чрезвычайно затрудняет проверку правильности конфигурации DI.Вместо этого позвольте данным времени выполнения проходить через вызовы методов построенных графов объектов.
Когда мы позволяем данным времени выполнения "проходить через вызовы методов построенных графов объектов", вы 'посмотрим, полезность абстрактных фабрик снизится.Они могут все еще использоваться, когда данные времени выполнения используются для выбора из нескольких зависимостей (по сравнению с введением данных времени выполнения в зависимость), но даже тогда абстрактные фабрики, как правило, не являются лучшим решением, как объяснено здесь .Таким образом, статья гласит:
Как правило, использование фабричной абстракции - это не дизайн, который учитывает своих потребителей.Согласно принципу внедрения зависимостей (DIP) абстракции должны определяться их клиентами, и поскольку фабрика увеличивает число зависимостей, от которых вынужден зависеть клиент, абстракция явно не создается в пользу клиента, и поэтому мы можемСчитайте, что это является нарушением DIP.
Вместо этого такие шаблоны, как Facade, Composite, Mediator и Proxy, как правило, являются лучшим решением.
Этоне означает, что в вашем приложении не может быть кода, создающего зависимости, но его не следует определять как абстракцию, используемую другими компонентами приложения.Вместо этого фабричное поведение должно быть заключено в адаптеры, которые определены как часть вашего корня композиции .
Когда у вас есть только эти фабричные логика и зависимости как часть вашего корня композициина самом деле не имеет значения, определяете ли вы IRepositoryFactory
или просто используете Func<IRepository>
для построения такой зависимости, поскольку IRepositoryFactory
также будет определен в корне композиции (поскольку приложение не имеет никакого смысла в использовании такихfactory).
Тем не менее, в редком случае, когда Абстрактная Фабрика является правильной абстракцией (что обычно случается, когда вы создаете фреймворк многократного использования), я нахожу использование фабричных интерфейсов гораздо более открытымчем использование делегатов.Это немного более многословно, но гораздо яснее, что означает такая вещь.IControllerFactory
является более целенаправленным раскрытием, чем Func<IController>
.
Я бы сказал, что это еще более верно для фабрик, которые не создают зависимости , а вместо значений данных.Взять, к примеру, пример внедрения Func<DateTime>
в конструктор.Что это на самом деле означает и какое значение оно возвращает?Это интуитивно понятно, что он возвращает DateTime.Now
, или он возвращает DateTime.Today
, или что-то еще?В этом случае было бы намного понятнее определить интерфейс ITimeProvider
с помощью метода GetCurrentTime()
.
ПРИМЕЧАНИЕ. Этот ответ был обновлен в июле 2017 года, чтобы отразить мои последние представления.