Я рефакторинг PHP- приложения, и я пытаюсь сделать это имеет много внедрения зависимостей (DI), насколько это возможно.
Я чувствую, что у меня есть хорошее представление о том, как это работает, и я, конечно, вижу, что мои классы становятся намного стройнее и надежнее.
Я делаю рефакторинг, чтобы я мог внедрить зависимость, а не создавать новый объект в классе, но в какой-то момент мне придется создать некоторые объекты, то есть использовать new
ключевое слово dreaded .
Проблема, с которой я сейчас столкнулся, заключается в том, в какой момент я могу создавать новые объекты? Похоже, я попаду в класс верхнего уровня, создавая множество новых объектов, так как больше некуда идти. Это неправильно.
Я читал некоторые блоги, которые используют фабричные классы для создания всех объектов, а затем ты вводишь фабрику в другие классы. Затем вы можете вызвать фабричные методы, и фабрика создаст для вас новый объект.
Моя забота о том, чтобы сделать это, теперь мои фабричные классы будут new
бесплатными для всех! Я думаю, что это может быть нормально, так как они являются фабричными классами, но есть ли какие-то правила, которых нужно придерживаться при использовании фабричного шаблона и DI, или я иду далеко от цели?
источник
new
. Конечно, есть несколько точек входа, где вам нужно вызвать контейнер IoC, но их не должно быть много. Обычно вы настраиваете IoC один раз, а затем запрашиваете разрешение одного класса для каждого запроса. В случае MVC это обычно контроллер.Ответы:
После нескольких поисков по этому поводу кажется (как упоминалось в комментарии выше) класс верхнего уровня, о котором я говорил, называется Composition Root .
Действительно, кажется приемлемым решением добавить создание всех объектов в этот корень композиции (или ссылаться на контейнер IoC отсюда).
Мое первоначальное беспокойство в связи с этим заключалось в том, что этот класс высшего уровня в конечном итоге будет немного беспорядочным. Это в некоторой степени верно, но плюсы весят минусы. Например, я вижу, что читаемость, тестируемость и удобство сопровождения всех моих других классов улучшились.
Класс верхнего уровня может быть немного грязным, завален
new
и ,set_property()
но я должен сказать , что я на самом деле предпочитаю иметь весь этот код в одном месте, а не разбросан по всем другим классамЕще одна полезная страница, обсуждающая хиты производительности этого метода здесь
источник
Фабричный класс будет
new
разбросан по всему. Это будет создание любого объекта, который вы запрашиваете, и, вероятно, зависимости этого объекта. Поскольку работа на фабриках заключается в том, чтобы создать правильный объект для васnew
в этом классе, это не плохо.DI так, чтобы у вас был слабосвязанный дизайн. Вы можете вносить изменения в свое приложение, изменяя зависимость, которая предоставляется каждому объекту. Делаем ваше приложение гибким, расширяемым и простым в тестировании.
На верхнем уровне у вас будет код, который будет создавать пару фабрик, настраивать соединения со службами и отправлять ответ. Он будет иметь достаточное количество
new
статических вызовов для создания экземпляров объектов, необходимых для вашего приложения. Это было бы, где это принадлежит.источник
Мои два цента здесь:
Вы не заявляете, используете ли вы среду внедрения зависимостей. Я думаю, что вы определенно должны. Используйте то, что дает вам необходимые функции: /programming/9348376/guice-like-dependency-injection-frameworks-in-php .
Обычно вы используете конфигурацию или центральную точку для создания экземпляров исходных объектов, составляющих ваше приложение. Контейнер создаст объекты для вас.
Затем вы получаете доступ к объектам (сервисам, поставщикам, контроллерам ...) через контейнер IoC. При необходимости он прозрачно создаст объект или предоставит ссылку на соответствующий существующий экземпляр.
Конечно, внутри вашей конкретной реализации объектов вы можете создавать экземпляры других объектов, для которых вам не нужен DI (структуры данных, пользовательские типы и т. Д.), Но это нормальное программирование.
Обычно вы используете Factory, если хотите, чтобы инфраструктура IoC создавала экземпляры некоторых объектов IoC через ваши фабрики (это необходимо, когда создание экземпляра конкретного объекта требует дополнительной работы). Если вы можете просто создавать свои объекты с помощью «new Object ()» и устанавливать некоторые свойства, вам не обязательно использовать шаблон Factory.
Другими словами, я бы сказал, что использование шаблона Factory для класса или группы классов зависит от того, как вы хотите моделировать эти классы, а не от того, используете ли вы DI (если ваша реализация DI явно не требует фабрики, что необычно).
Вы также настраиваете свою инфраструктуру IoC для использования Factory, когда вы используете стороннюю библиотеку, которая уже требует использования Factory. В этом случае у вас нет контроля над этим, и вам нужно сказать вашему контейнеру IoC: «эй, когда я запрашиваю один из этих интерфейсов, вы должны использовать эту фабрику, чтобы предоставить мне соответствующий экземпляр».
В этом случае звучит так, что вам не нужно использовать шаблоны Factory для этих объектов / служб / контроллеров / чего бы то ни было, и вы можете просто настроить свой IoC для создания экземпляра с помощью «нового» соответствующего класса и внедрения всего остального.
Я надеюсь, что это помогает.
источник
doing DI manually beats the whole purpose of using an Inversion of Control container
- Если под этим вы подразумеваете «... который централизует ваши зависимости в файле конфигурации», то вы правы, потому что это все, что делает контейнер IoC. Настоящая цель DI - разделение, и вы можете сделать это, предоставив свои зависимости в методе конструктора. Для этого вам вообще не нужна структура DI.