Паттерны проектирования в PHP 8: адаптер

Здравствуйте!
Предположим, мы решили создать функцию, которая будет уведомлять менеджера аккаунта о новом зарегистрированном пользователе. Мы создадим эту функцию, которая будет вызывать универсальную функцию send() для отправки сообщений, которая принимает две строки — тему сообщения и его текст.

function messageAboutNewClient(): void
{
    send('New client', 'We have a new client...');
}
Вход в полноэкранный режим Выход из полноэкранного режима

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

function messageAboutNewClient(NotificationInterface $notification): void
{
    $notification->send('New client', 'We have a new client...');
}
Вход в полноэкранный режим Выйти из полноэкранного режима

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

interface NotificationInterface
{
    public function send(string $title, string $message): void;
}
Вход в полноэкранный режим Выход из полноэкранного режима

Функция send() из начала статьи реализовала отправку писем с помощью стандартного метода PHP mail, давайте создадим класс, реализующий наш интерфейс на основе этой функции.

class EmailNotification implements NotificationInterface
{
    public function __construct(public readonly string $adminEmail)
    {
    }

    public function send(string $title, string $message): void
    {
        // Standard php function for sending emails
        mail($this->adminEmail, $title, $message);
    }
}
Вход в полноэкранный режим Выйти из полноэкранного режима

И вот как вы можете отправлять сообщения о новых клиентах:

$notification = new EmailNotification('mail@zhukmax.com');
messageAboutNewClient($notification);
Вход в полноэкранный режим Выход из полноэкранного режима

Некоторое время назад я написал библиотеку для отправки SMS-сообщений, которую выложил на github под свободной лицензией. Я хотел бы включить ее в проект. Но есть проблема: библиотека работает немного иначе, чем наш интерфейс, у нее даже нет метода send. И здесь на помощь приходит паттерн проектирования Adapter, который позволяет безболезненно связать библиотеку с ее интерфейсами и наш проект с помощью специального класса-прослойки.

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

use Exception;
use ZhukmaxSmscApi;

class SmsNotification implements NotificationInterface
{
    private Api $service;
    private array $phones;

    /**
     * @param array $phones
     */
    public function setPhones(array $phones): void
    {
        $this->phones = $phones;
    }

    /**
     * @throws Exception
     */
    public function __construct(array $config, string $from)
    {
        $this->service = new Api(
            $config['login'],
            $config['password'],
            [
                'https' => $config['https'],
                'charset' => $config['charset'],
                'from' => $from,
                'post' => true
            ]
        );
    }

    public function send(string $title, string $message): void
    {
        $this->service->sendSms($this->phones, `$title $message`);
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы можем вызывать функцию messageAboutNewClient для отправки сообщений о новых клиентах, ничего в ней не меняя. Поскольку библиотека может выбрасывать исключения, мы обернем все с помощью try / catch.

try {
    $notification = new SmsNotification($config, 'mail@zhukmax.com');
    $notification->setPhones([+19001234567]);
    messageAboutNewClient($notification);
} catch (Exception $e) {
    // ...
}
Вход в полноэкранный режим Выход из полноэкранного режима

© Photo by Tangerine Chan on Unsplash

Оцените статью
devanswers.ru
Добавить комментарий