шаблон проектирования для переключения поставщиков электронной почты в коде - PullRequest
0 голосов
/ 20 ноября 2018

Нам нужно отправлять электронные письма в нашем приложении 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 (), и я готов идти дальше.

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

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

1 Ответ

0 голосов
/ 20 ноября 2018

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

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

Загляните в класс 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 может отправлять электронные письма, просто посмотрев на свою подпись. Отправка электронной почты, выполнение операций ввода-вывода / базы данных / сети ... являются важными вещами и всегда должны быть в курсе.

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

...