Reg.ru: домены и хостинг

Крупнейший регистратор и хостинг-провайдер в России.

Более 2 миллионов доменных имен на обслуживании.

Продвижение, почта для домена, решения для бизнеса.

Более 700 тыс. клиентов по всему миру уже сделали свой выбор.

Перейти на сайт->

Бесплатный Курс "Практика HTML5 и CSS3"

Освойте бесплатно пошаговый видеокурс

по основам адаптивной верстки

на HTML5 и CSS3 с полного нуля.

Начать->

Фреймворк Bootstrap: быстрая адаптивная вёрстка

Пошаговый видеокурс по основам адаптивной верстки в фреймворке Bootstrap.

Научитесь верстать просто, быстро и качественно, используя мощный и практичный инструмент.

Верстайте на заказ и получайте деньги.

Получить в подарок->

Бесплатный курс "Сайт на WordPress"

Хотите освоить CMS WordPress?

Получите уроки по дизайну и верстке сайта на WordPress.

Научитесь работать с темами и нарезать макет.

Бесплатный видеокурс по рисованию дизайна сайта, его верстке и установке на CMS WordPress!

Получить в подарок->

*Наведите курсор мыши для приостановки прокрутки.


Шаблон проектирования «Адаптер»

Предыдущий материал из этой серии вы можете прочитать здесь.

В этой статье мы продолжаем разбирать шаблоны проектирования, и сегодня наша цель - шаблон под названием "Адаптер".

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

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

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

Проблема


<?php
class PayPal {

    public function __construct() {
        // здесь ваш код //
    }

    public function sendPayment($amount) {
        // оплата через PayPal //
        echo "Оплата через PayPal: ". $amount;
    }
}

$paypal = new PayPal();
$paypal->sendPayment('2629');

В коде выше мы видим инициализацию класса PayPal для оплаты некой суммы. Здесь мы непосредственно создаем экземпляр класса PayPal и производим оплату.

Данный код должен использоваться в нескольких местах, и мы применяем для проведения оплаты такую конструкцию:


$paypal->sendPayment('сумма');

Некоторое время назад в PayPal изменили имя метода с SendPayment на payAmount. Это ясно дает нам понять суть проблемы, ведь мы пока используем старый метод.

Теперь нам нужно заменить все вызовы метода SendPayment на payAmount. Представьте, сколько кода нам нужно будет поменять и сколько времени потратить на повторное тестирование.

Решение

Одно из решений этой задачи - использование шаблона проектирования "Адаптор".

Википедия гласит:

"Адаптер" - шаблон проектирования, который делает возможным использование интерфейса существующего класса из другого интерфейса. Часто он используется для того, чтобы заставить уже имеющиеся классы работать с другими классами без модификации их кода.

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

Давайте посмотрим на код, показывающий работу шаблона в действии:


// Неизменный класс PayPal
class PayPal {

    public function __construct() {
        // здесь ваш код //
    }

    public function sendPayment($amount) {
        // оплата через PayPal //
        echo "Оплата через PayPal: ". $amount;
    }
}

// простой интерфейс для всех создаваемых Адаптеров
interface paymentAdapter {
    public function pay($amount);
}

class paypalAdapter implements paymentAdapter {

    private $paypal;

    public function __construct(PayPal $paypal) {
        $this->paypal = $paypal;
    }

    public function pay($amount) {
        $this->paypal->sendPayment($amount);
    }
}

Посмотрите на код выше и заметите, что в код класса PayPal не было внесено изменений. Вместо этого мы создали один интерфейс для нашего платежного Адаптера и класс Адаптера для PayPal.

И далее мы уже работаем с объектом класса-Адаптера вместо того, чтобы использовать непосредственно класс PayPal.

В процессе создания объекта из класса-Адаптера мы передаем ему в качестве аргумента основной неизменяемый класс PayPal для того, чтобы класс-Адаптер мог иметь ссылку на главный класс и мог вызывать методы этого класса.

Применяем мы это следующим образом:


// клиентский код
$paypal = new paypalAdapter(new PayPal());
$paypal->pay('2629');

Теперь представьте, что PayPal меняет имя метода с sendPayment на payAmount. Теперь нам нужно всего лишь внести изменения в класс paypalAdapter. Давайте посмотрим на измененный код Адаптера, в котором есть лишь одна правка:


class paypalAdapter implements paymentAdapter {

    private $paypal;

    public function __construct(PayPal $paypal) {
        $this->paypal = $paypal;
    }

    public function pay($amount) {
        $this->paypal->payAmount($amount);
    }
}

Вот так просто. Всего одно изменение.

Добавление нового Адаптера

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

Пусть, у нас есть еще вариант оплаты с помощью MoneyBooker.

Как и в предыдущем случае, мы не будем напрямую использовать класс MoneyBooker, а воспользуемся тем же адаптером, что и в случае с PayPal.


// Неизменный класс MoneyBooker
class MoneyBooker {

    public function __construct() {
        // ваш код здесь //
    }

    public function doPayment($amount) {
        // оплата через MoneyBooker //
        echo "Оплата через MoneyBooker: ".  $amount;
    }
}

// MoneyBooker-Адаптор
class moneybookerAdapter implements paymentAdapter {

    private $moneybooker;

    public function __construct(MoneyBooker $moneybooker) {
        $this->moneybooker = $moneybooker;
    }

    public function pay($amount) {
        $this->moneybooker->doPayment($amount);
    }
}

// Клиентский код
$moneybooker = new moneybookerAdapter(new MoneyBooker());
$moneybooker->pay('2629');

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

Вывод

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

Понравился материал и хотите отблагодарить?
Просто поделитесь с друзьями и коллегами!


Смотрите также:

PHP: Получение информации об объекте или классе, методах, свойствах и наследовании

PHP: Получение информации об объекте или классе, методах, свойствах и наследовании

CodeIgniter: жив или мертв?

CodeIgniter: жив или мертв?

Функции обратного вызова, анонимные функции и механизм замыканий

Функции обратного вызова, анонимные функции и механизм замыканий

Применение функции к каждому элементу массива

Применение функции к каждому элементу массива

Слияние массивов. Преобразование массива в строку

Слияние массивов. Преобразование массива в строку

Деструктор и копирование объектов с помощью метода __clone()

Деструктор и копирование объектов с помощью метода __clone()

Эволюция веб-разработчика или Почему фреймворк - это хорошо?

Эволюция веб-разработчика или Почему фреймворк - это хорошо?

Магические методы в PHP или методы-перехватчики (сеттеры, геттеры и др.)

Магические методы в PHP или методы-перехватчики (сеттеры, геттеры и др.)

PHP: Удаление элементов массива

PHP: Удаление элементов массива

Ключевое слово final (завершенные классы и методы в PHP)

Ключевое слово final (завершенные классы и методы в PHP)

50 классных сервисов, программ и сайтов для веб-разработчиков

50 классных сервисов, программ и сайтов для веб-разработчиков

Наверх