Программирование, Шаблоны проектирования

Шаблон «Адаптер» (Adapter pattern)

Уж очень напрашивается иллюстрация ниже. Наверное, вы уже догадались, в чем дело?

1

А теперь по порядку. Начнем с определения:

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

Рассмотрим определение в терминах вилка-розетка.

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

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

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


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

Предположим, что разрабатывается сайт (интернет-магазин), поддерживающий разные виды оплаты:

  • Бета-Банк
  • ПриветБанк
  • BayPal

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

Большинство платежных систем предоставляют SDK — класс или набор классов для работы с платежной системой. Представим, что для каждого из методов оплаты существует PHP класс, с нужным нам методом:

После того, как покупатель выбрал метод, мы создаем объект метода оплаты (одного из классов выше):

Здесь очень уместным будет еще один шаблон — стратегия. Можете прочесть как и зачем его использовать позже.

По задумке осуществить оплату было бы очень удобно вот так:

Но… Есть проблема. Так как SDK классы были «разработаны разными людьми», в разное время, без каких-либо договоренностей между собой, то названия методов и порядок аргументов в них отличаются. Хотя они делают одно и те же действие — переводят X денег на карту N.

Что делать?

Правильно! Применить «переходник» — адаптер. Такой же, какой вы применяете для розетки, только для класса. Решение может выглядеть вот так:

В коде выше я создал два адаптера для классов BetaBank и PrivetBank. Методы pay() в каждом из них вызывают соответствующие методы SDK классов с правильными именами и порядком аргументов.

Интерфейс PaymentAdapterInterface используется для того, чтоб гарантировать существование метода pay() в конкретной реализации класса-адаптера.

Теперь в клиентском коде осуществлять оплату можно вот так:


Вместо выводов

Паттерн адаптер обеспечивает возможность работы с объектами, у которых разные интерфейсы. При этом пропадает необходимость переписывать существующий код к требуемому интерфейсу.

Поделитесь с друзьями или сохраните себе
  •  
  •  
  •  
  •  
  •  
  •  
  •  

One Comment

Напишите комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *


пять × три =