Внедрение зависимостей: в какой момент мне разрешено создавать новый объект?

13

Я рефакторинг PHP- приложения, и я пытаюсь сделать это имеет много внедрения зависимостей (DI), насколько это возможно.

Я чувствую, что у меня есть хорошее представление о том, как это работает, и я, конечно, вижу, что мои классы становятся намного стройнее и надежнее.

Я делаю рефакторинг, чтобы я мог внедрить зависимость, а не создавать новый объект в классе, но в какой-то момент мне придется создать некоторые объекты, то есть использовать newключевое слово dreaded .

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

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

Моя забота о том, чтобы сделать это, теперь мои фабричные классы будут newбесплатными для всех! Я думаю, что это может быть нормально, так как они являются фабричными классами, но есть ли какие-то правила, которых нужно придерживаться при использовании фабричного шаблона и DI, или я иду далеко от цели?

Gaz_Edge
источник
Я рекомендую IoC для услуг и политик. Для моделей или вспомогательных классов я бы просто использовал new. Конечно, есть несколько точек входа, где вам нужно вызвать контейнер IoC, но их не должно быть много. Обычно вы настраиваете IoC один раз, а затем запрашиваете разрешение одного класса для каждого запроса. В случае MVC это обычно контроллер.
CodesInChaos
Класс верхнего уровня, который вы упоминаете, является частью Composition Root. Это далеко не так.
Соотношение

Ответы:

12

После нескольких поисков по этому поводу кажется (как упоминалось в комментарии выше) класс верхнего уровня, о котором я говорил, называется Composition Root .

Действительно, кажется приемлемым решением добавить создание всех объектов в этот корень композиции (или ссылаться на контейнер IoC отсюда).

Мое первоначальное беспокойство в связи с этим заключалось в том, что этот класс высшего уровня в конечном итоге будет немного беспорядочным. Это в некоторой степени верно, но плюсы весят минусы. Например, я вижу, что читаемость, тестируемость и удобство сопровождения всех моих других классов улучшились.

Класс верхнего уровня может быть немного грязным, завален newи , set_property()но я должен сказать , что я на самом деле предпочитаю иметь весь этот код в одном месте, а не разбросан по всем другим классам

Еще одна полезная страница, обсуждающая хиты производительности этого метода здесь

Gaz_Edge
источник
1
+1, потому что я никогда раньше не слышал о «корне композиции».
c_maker
2

Фабричный класс будет newразбросан по всему. Это будет создание любого объекта, который вы запрашиваете, и, вероятно, зависимости этого объекта. Поскольку работа на фабриках заключается в том, чтобы создать правильный объект для вас newв этом классе, это не плохо.

DI так, чтобы у вас был слабосвязанный дизайн. Вы можете вносить изменения в свое приложение, изменяя зависимость, которая предоставляется каждому объекту. Делаем ваше приложение гибким, расширяемым и простым в тестировании.

На верхнем уровне у вас будет код, который будет создавать пару фабрик, настраивать соединения со службами и отправлять ответ. Он будет иметь достаточное количество newстатических вызовов для создания экземпляров объектов, необходимых для вашего приложения. Это было бы, где это принадлежит.

Schleis
источник
-2

Мои два цента здесь:

Я рефакторинг PHP-приложения, и я пытаюсь сделать имеет много инъекций зависимостей, насколько это возможно

Вы не заявляете, используете ли вы среду внедрения зависимостей. Я думаю, что вы определенно должны. Используйте то, что дает вам необходимые функции: /programming/9348376/guice-like-dependency-injection-frameworks-in-php .

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

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

Затем вы получаете доступ к объектам (сервисам, поставщикам, контроллерам ...) через контейнер IoC. При необходимости он прозрачно создаст объект или предоставит ссылку на соответствующий существующий экземпляр.

Конечно, внутри вашей конкретной реализации объектов вы можете создавать экземпляры других объектов, для которых вам не нужен DI (структуры данных, пользовательские типы и т. Д.), Но это нормальное программирование.

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

Обычно вы используете Factory, если хотите, чтобы инфраструктура IoC создавала экземпляры некоторых объектов IoC через ваши фабрики (это необходимо, когда создание экземпляра конкретного объекта требует дополнительной работы). Если вы можете просто создавать свои объекты с помощью «new Object ()» и устанавливать некоторые свойства, вам не обязательно использовать шаблон Factory.

Другими словами, я бы сказал, что использование шаблона Factory для класса или группы классов зависит от того, как вы хотите моделировать эти классы, а не от того, используете ли вы DI (если ваша реализация DI явно не требует фабрики, что необычно).

Вы также настраиваете свою инфраструктуру IoC для использования Factory, когда вы используете стороннюю библиотеку, которая уже требует использования Factory. В этом случае у вас нет контроля над этим, и вам нужно сказать вашему контейнеру IoC: «эй, когда я запрашиваю один из этих интерфейсов, вы должны использовать эту фабрику, чтобы предоставить мне соответствующий экземпляр».

Моя забота о том, чтобы сделать это, теперь мои фабричные классы станут новыми бесплатными для всех! Я думаю, это может быть нормально, так как они являются фабричными классами, но есть ли какие-то правила, которых нужно придерживаться при использовании фабричных шаблонов и DI, или я иду далеко от цели.

В этом случае звучит так, что вам не нужно использовать шаблоны Factory для этих объектов / служб / контроллеров / чего бы то ни было, и вы можете просто настроить свой IoC для создания экземпляра с помощью «нового» соответствующего класса и внедрения всего остального.

Я надеюсь, что это помогает.

jjmontes
источник
спасибо за ответ, но, безусловно, контейнер IoC является «классом верхнего уровня», о котором я говорил. Если я могу только создавать объекты там, это будет правильный беспорядок.
Gaz_Edge
4
doing DI manually beats the whole purpose of using an Inversion of Control container- Если под этим вы подразумеваете «... который централизует ваши зависимости в файле конфигурации», то вы правы, потому что это все, что делает контейнер IoC. Настоящая цель DI - разделение, и вы можете сделать это, предоставив свои зависимости в методе конструктора. Для этого вам вообще не нужна структура DI.
Роберт Харви
ммм, вы не создаете объекты, вы запрашиваете у них контейнер IoC (откуда угодно) или используете инъекцию поля / аргумента, чтобы ваши классы автоматически вводили соответствующие классы, всегда создаваемые контейнером IoC.
jjmontes
1
Я бы согласился, что вам нужны рамки для очень больших приложений. Многие приложения не так велики и не выигрывают от дополнительной сложности использования инфраструктуры DI.
Роберт Харви
2
Я не сказал, что это было. Я просто сказал, что вам не нужен DI-контейнер для этого.
Роберт Харви