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