Когда я должен использовать Внедрение зависимости и когда служебные методы?

У меня есть Java проект EE с Spring контейнер МОК.

Я только что нашел в Utils статический метод класса sendMail(long list of params). Я не знаю, почему, но я чувствую, что выглядело бы лучше, если бы у нас был отдельный класс (боб Spring с одноэлементным объемом), который будет ответственен за отправку электронного письма. Но я не могу найти аргументы, которые могут доказать мое положение.

Так, есть ли какие-либо профессионалы (или недостатки) в использовании DI в этой (довольно общей) ситуации?

5
задан Roman 3 May 2010 в 14:49
поделиться

6 ответов

Если классы, которым нужно отправлять электронную почту, используют интерфейс MailSender (имя примера) вместо метода static Utils.sendMail(...), то вы можете легко проводить модульное тестирование этих классов, подставляя в свои модульные тесты макет/другую реализацию MailSender вместо использования реальной реализации.

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

Если классы используют статический метод, как вы описали, то вы не сможете изолированно протестировать поведение этих классов без фактической отправки электронной почты - в этом случае это не будет эффективным изолированным модульным тестом, поскольку вы будете зависеть от поведения 1) кода отправки почты 2) сервера исходящей почты и т. д.

6
ответ дан 18 December 2019 в 11:54
поделиться

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

В данном случае отправка почты, вероятно, зависит от внешнего состояния (доступности почтового сервера) и вызывает внешние эффекты, которых вы вполне можете захотеть избежать (отправка электронной почты). Для разработки и тестирования вы, вероятно, вообще не захотите отправлять электронную почту. В других случаях вы можете захотеть проверить, что письмо было отправлено, но как это сделать, если почта действительно отправляется? Устанавливать какую-то сложную систему для проверки реального почтового ящика на наличие письма?

Если вы внедрите интерфейс, представляющий MailSender, вы можете предоставить NoopMailSender, который ничего не делает, когда вас не волнует отправляемое письмо, и StubMailSender, который собирает List писем, отправленных через него, когда вы хотите иметь возможность проверить, что определенные письма были отправлены вашим кодом.

0
ответ дан 18 December 2019 в 11:54
поделиться

Классы типа Util, которые содержат мешанину обычно статических функций, обычно не являются хорошими вещами. Я даже видел такой класс под названием UglyGlobals в одном проекте, над которым я работал. По крайней мере, они были честны в этом! Как правило, вы правы. Что-то вроде mailing - отличный кандидат на превращение в singleton bean, который будет инжектироваться.

4
ответ дан 18 December 2019 в 11:54
поделиться

Spring Mail

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

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

Статические методы против инъекции зависимостей

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

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

0
ответ дан 18 December 2019 в 11:54
поделиться

Да! Я приведу вам пример из моего собственного недавнего опыта.

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

Такая простая вещь, как отправка электронной почты, может стать тем, что вы захотите изменить в будущем. Внедрение реализации значительно упростит эту задачу.

5
ответ дан 18 December 2019 в 11:54
поделиться

DI упрощает имитацию вашей реализации для написания тестов. Например, предположим, что вы хотите протестировать процесс сброса пароля. С жестко запрограммированным Utils.sendMail () ваш тестовый код будет вынужден создать имитацию SMTP-сервера, прочитать и проанализировать электронную почту, а затем щелкнуть ссылку для сброса пароля. Если бы вы использовали DI, вы могли бы передать фиктивный объект Emailer . Таким образом, вы можете писать сверхбыстрые модульные тесты, не беспокоясь о внешней интеграции.

Вы также можете легко поменять местами реализации. Например, в Google App Engine есть настраиваемый API sendMail, поэтому вам будет сложно поддерживать версию кода GAE и версию без GAE одновременно. (Для аргументации просто предположим, что переход на GAE настолько прост. Очевидно, это не так).

Наконец, ваш код стал более модульным. Конкретный класс (ResetPassword) может просто зависеть от Util.sendMail (), но Util может быть кухонной раковиной с методами, позволяющими делать все под солнцем. Итак, если вы хотите повторно использовать ResetPassword в другом проекте, вам необходимо скопировать весь класс Utils, а также несколько зависимых jar-файлов, необходимых для работы Utils. Это не лучший вариант.

0
ответ дан 18 December 2019 в 11:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: