шаблон проектирования для переключения поставщиков электронной почты в коде

Нам нужно отправлять электронные письма в нашем приложении php (кто не делает). Первоначально, когда наше приложение было в младенчестве, мы использовали просто linux sendmail.
Немного продвигаясь вперед, мы переключились на собственный SMTP-сервер. Это означает изменение кода в каждом файле, который имеет функцию, связанную с электронной почтой.
Год спустя мы перешли на AWS, и нам пришлось снова изменить код, чтобы начать пользоваться сервисом электронной почты AWS.
Теперь мы перешли в облако Google и снова изменили код электронной почты для использования стороннего поставщика.

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

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

Но из-за своей жизни я не могу понять, каким будет выход из этого беспорядка.

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

Ее мой взгляд на это

class EmailGateway()
{
private $emailer;
public function __construct($someEmailProvider)
{
$this->emailer = $someEmailProvider;
}

public function send($from, $to, $subject, $bodyText, $bodyHtml="")
{

this->emailer->send($from, $to, $subject, $bodyText, $bodyHtml="");
}
}

И тогда в моем коде все, что мне нужно, это назвать как

# Gmail?
$mailGateway = new EmailGateway(new GmailEmailer("username", "password"));

# local?
$mailGateway = new EmailGateway(new SendMailer());

# SMTP?
$mailGateway = new EmailGateway(new MyMailServerMailer("192.168.0.3", "no_user", "secret_password"));

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

class EmailService()
{
public static function currentProvider(): EmailProviderInterface
{

return new MyMailServerMailer("192.168.0.3", "no_user", "secret_password");

}
}

Это сделает мой код вызывающего абонента еще проще

# SMTP?/GMAIL?/Local?/Whatever
$mailGateway = new EmailGateway(EmailService::currentProvider());

Поэтому всякий раз, когда мне нужно сменить провайдера, все, что я буду делать, — это сменить текучесть currentProvider (), и я готов идти дальше.

Я делаю это правильно?
Это правильный шаблон стратегии вообще?
Должен ли я заботиться о том, какой это шаблон, если он может решить мою проблему?

Есть ли лучший способ вытащить себя из этого постоянно растущего беспорядка?

0

Решение

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

Тем не менее, вы можете сделать свой дизайн проще и лучше.

Заглянуть в EmailGateway класс: он не делает ничего существенного. Он имеет такой же интерфейс с EmailProvider и просто делегирует send задача к EmailProvider,

Таким образом, вы могли бы просто иметь интерфейс с именем EmailProvider — Я использую Java, но это должно быть легко перевести на PHP:

interface EmailProvider {
void send(String from, String to, String subject, String bodyText, String bodyHtml);
}

А потом несколько реализаций:

class GoogleEmailProvider implements EmailProvider {
public GoogleEmailProvider (String username, String password) {
...
}
public void send(String from, String to, String subject, String bodyText, String bodyHtml) {
...
}
}
// and so on ...

На CompositionRoot вашего приложения (например, main метод), вы просто создаете один экземпляр EmailProvider что вам нужно:

EmailProvider emailProvider = new GoogleEmailProvider("username", "password");

Затем вы можете передать этот экземпляр в любое место, где необходимо отправить электронную почту:

Foo foo = new Foo(emailProvider);

Этот дизайн предлагает некоторые преимущества. Во-первых, проще провести модульное тестирование таких классов, как Foo, Вы всегда можете написать MockEmailProvider и передать его Foo, Во-вторых, пользователи классов, как Foo должно быть легко осознавать, что Foo можно отправлять электронные письма, просто посмотрев на свою подпись. Отправка электронной почты, выполнение операций ввода-вывода / базы данных / сети … являются важными вещами и всегда должны быть хорошо осведомлены.

Надеюсь это поможет.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]