При использовании внедрения зависимостей, куда идут все новые операторы? - PullRequest
6 голосов
/ 17 июня 2011

Я читал о внедрении зависимостей и понимаю основную концепцию, согласно которой метод должен получать то, что ему нужно, от вызывающего, а не создавать такие элементы самому. В результате, new операторы удаляются из метода почти полностью (некоторые базовые объекты, конечно, будут освобождены - один из примеров, который я нашел, был для таких вещей, как StringBuilder s, которые кажутся безумными иметь пройти).

Мой вопрос звучит обманчиво простым, но я подозреваю, что ответ на самом деле довольно сложный: куда делись все операторы new?

Поначалу ответ кажется простым: оператор new просто выталкивается в метод, который вызывает метод, которому нужен объект. Проблема с этим, однако, заключается в том, что вызывающий метод, вероятно, также тестируется, и поэтому new подталкивается от вызывающего метода к вызывающему методу, пока в конечном итоге вы не доберетесь до корневого метода (который на данный момент кажется безумным непроверенным), который создает непристойное количество объектов для использования в различных точках стека вызовов. Ситуация становится еще более сложной, если учесть, что этот корневой метод является корнем множества других методов, и поэтому для каждого случая потребуется создание объектов. Это также создает проблему с производительностью, поскольку вы быстро останетесь с большим количеством объектов, которые фактически никогда не используются, но которые должны быть созданы в любом случае «на всякий случай».

Для меня совершенно очевидно, что я упустил некоторые важные знания, которые настолько очевидны для других разработчиков, что никто не подумает описать это в сообщении в блоге. Однако я, очевидно, не могу знать, чего я не знаю, поэтому я смиренно прошу, чтобы я раскрыл секрет: куда делись все операторы new?

Я должен упомянуть, что я занимаюсь разработкой на PHP, поэтому каждый запрос начинается с одной и той же точки, и кажется, что корневой "метод" в index.php должен охватывать все, что приложение может do, чтобы гарантировать, что он предоставляет объект для всего, что сделает в текущем запросе. Опять же, здесь есть фундаментальное недоразумение, и я бы очень хотел его исправить.

Ответы [ 4 ]

5 голосов
/ 18 июня 2011

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

Также обратите внимание: внедрение зависимостей предназначено для служб, а не длясущности или объекты стоимости.Например, инъекция IUserRepository имеет смысл, но IUser не так уж много --- и, конечно, не StringBuilder с.Это может помочь прояснить вещи в свете ваших скобок о более примитивных типах: на самом деле разделение не в том, насколько они примитивны, а в том, какова их роль в системе.

3 голосов
/ 17 июня 2011

Совершенно очевидно, что оператор new отправляется в контейнер DI, когда происходит создание всех экземпляров.

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

Для разработки на PHP я предлагаю вам взглянуть на Symfony Framework , который очень хорошо реализует DI и является примером безупречной и чистой архитектуры.

1 голос
/ 17 июня 2011

Внедрение зависимостей обычно используется в приложениях MVC.В этих случаях «new», как вы его называете, обычно переходят на уровень Controler.

При вызове модели Controler создает зависимости и передает их в модель, а затем вызываетбизнес-методы, представленные моделью.

Но не думайте, что DI - это "удаление new s".Речь идет о разъединении.Чем меньше классов создают (и, следовательно, «знают») другие классы, тем меньше их может повредить изменение в этих других классах.

Другая цель - облегчить тестирование.Если у вас есть метод, который должен составлять и отправлять почту, сложно проверить, правильно ли составлена ​​почта.Однако, если вы удалите зависимость фактической отправки почты из этого класса в другой класс и дадите объект, который может отправлять почту этому методу, только при написании теста вместо того, чтобы давать этому методу объект, который можетдействительно отправлять почту, вы дадите этому методу объект, который только фальсифицирует отправку почты .Вы видите смысл?

0 голосов
/ 18 июня 2011

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

Поэтому вместо new ConcreteType() вы спрашиваете контейнер container.Get<Interface/Type>().

Тем не менее, поскольку я читаю комментарии, указывающие на то, что вы только начинаете, я бы рекомендовал не использовать собственную DI Framework (это обычное время). Используйте и изучайте код для существующих функциональных библиотек DI, таких как MEF / Unity / любой другой.

...