Инъекция зависимостей приводит к размножению фабрик? - PullRequest
7 голосов
/ 24 мая 2011

Я всегда чувствовал себя некомфортно, когда имел дело с классами, которым нужно было создать множество объектов, поскольку я использовал принципы внедрения зависимостей.

Например, допустим, у меня есть класс, который должен вызывать много разных видов событий. Каждое событие имеет свой тип, поэтому я хотел бы иметь разные фабрики для каждого типа событий. Если у меня будет 10 мероприятий, то мне нужно будет 10 заводов. Это не кажется хорошим. Я мог бы также иметь одну фабрику для всех видов событий, но это тоже не кажется правильным.

(для толпы C # я не говорю о событиях .NET здесь. Это был просто пример, чтобы добраться до сути, просто думайте о них как о регулярных классах!)

Это был просто пример. У меня нет проблем с наличием фабрики здесь или там, но в некоторых типах проектов, где нужно создавать много объектов во время выполнения, мне кажется, что я должен создать фабрику почти для каждого класса, который я определяю!

Как вы справляетесь с этой ситуацией? Я что-то упустил?

Я видел, как люди просто передавали ссылку на IoC-контейнер, который они используют, но мне это не кажется полезным. ИМО, модель домена даже не должна знать, что используется контейнер IoC!

Спасибо

Ответы [ 2 ]

6 голосов
/ 24 мая 2011

Я был поклонником инъекций конструктора до тех пор, пока я знал о DI, потому что, на мой взгляд, это конструктор для . В нем говорится «Мне нужны экземпляры следующих классов / интерфейсов для выполнения моей работы» - например, передайте мне File и PrintWriter, и я напишу содержимое первого последнему.

И, конечно, это означает, что код не знает о структуре DI, так как класс просто создается с передачей требуемых зависимостей. Кроме того, я не вижу необходимости в фабриках в этом сценарии, поскольку класс является собственной фабрикой через конструктор.


Что касается сценария, который вы определили во втором абзаце, я не уверен, что это строго связано с внедрением зависимостей, а просто с дизайном иерархии классов и обязанностей. Либо Ваш класс точно знает, как создать Event, который соответствует, например, неудачный вход в систему, и в этом случае он делает это (то есть, вызывая конструктор класса); или , он не знает, как, и в этом случае ему придется делегировать некоторому виду фабрики для создания Event.

И в этом случае вы можете настроить свой класс на использование одной и той же фабрики для создания всех десяти событий (определить интерфейс EventFactory с 10 методами), или вы можете определить отдельный интерфейс фабрики (и реализацию) для каждого типа события, которое необходимо построить. В этом последнем случае вам также необходимо передать десять различных фабрик в конструктор вашего основного класса.

Но опять же - это не имеет ничего общего с DI ИМХО, это вопрос того, как вы разрабатываете свои классы для гибкости (или «корпоративности») против прямолинейности. По моему мнению, они ортогональны; сначала вы определяете, в каких соавторах нуждается ваш класс (десять фабрик, одна фабрика или ноль фабрик) и , а затем вы используете DI для обеспечения этих зависимостей. Наличие или отсутствие DI не должно влиять на дизайн вашего класса.

2 голосов
/ 24 мая 2011

Нет ничего плохого в классе, который создает множество других объектов.Вместо этого этот класс должен рассматриваться как совокупный корневой объект домена.Что касается разных «типов» сущностей, если вы предполагаете, что они реализуют один и тот же интерфейс или наследуют от одного и того же базового класса, то, передавая аргумент type в Factory.create(type), я обычно решаю эту проблему.Внутренние элементы create() могут делегировать другим классам, таким как шаблон Стратегии, но API, стоящий перед клиентом, прост.

Теперь, если вы создаете фабрику для каждого класса, с которым вы имеете дело, это звучит как нечто анти-шаблонное.Изучите шаблон совокупного корня, упомянутый выше, и посмотрите, можете ли вы организовать свои объекты в графы - вы должны это сделать - так, чтобы для генерации всего графа хватило одной фабрики.

Что касается IoC, модель домена не должна знать о контейнере.Когда у меня есть сущности, которым нужны ссылки на синглтоны - обычно фабрики - в контейнере, я обычно внедряю одну фабрику в другую как таковую:

class FactoryA {
    void setFactoryB(FactoryB factoryB) { /* sets into state */ }
    EntityA create(Enum type) {
        EntityA entityA = new EntityA();
        /* DI FactoryB - this method is probably default access */
        entityA.setFactoryB(getFactoryB());
    }
}

class FactoryB {}

Так что в приведенном выше примере и FactoryA, и FactoryB являются синглетонамиуправляется контейнером IoC.EntityA нужна ссылка на FactoryB, поэтому FactoryA внедряется со ссылкой на FactoryB, которая передается внутри метода create().

...