Паттерн «Адаптер»
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy. Урок 76 из 91.
Паттерн Adapter — это структурный шаблон проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он действует как мост между двумя интерфейсами, преобразуя вызовы из одного формата в другой.
Представьте, что вы создаёте application для обработки платежей и вам нужно интегрировать стороннюю payment library. library отлично работает, но its interface не соответствует тому, что ожидает ваш код. Вместо того чтобы переписывать application целиком, вы создаёте adapter, который обеспечивает перевод между ними.
<?php
// Интерфейс, который ожидает ваше приложение
interface PaymentProcessor {
public function pay(float $amount): string;
}
// Сторонняя библиотека с другим интерфейсом
class StripeAPI {
public function createCharge(int $cents, string $currency): string {
return "Charged {$cents} {$currency} via Stripe";
}
}
adapter implements ваш ожидаемый interface, при этом внутри использует class стороннего разработчика:
<?php
class StripeAdapter implements PaymentProcessor {
public function __construct(private StripeAPI $stripe) {}
public function pay(float $amount): string {
$cents = (int)($amount * 100);
return $this->stripe->createCharge($cents, 'USD');
}
}
$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);
Output:
Charged 2999 USD via Stripeadapter converts доллары в центы и вызывает соответствующий method. Ваш application-код знает только о PaymentProcessor, оставаясь блаженно не осведомлённым о специфических требованиях Stripe. Если позже вы переключитесь на different платёжного провайдера, вы просто создадите новый adapter, не изменяя существующий код.
Задание
ЛегкоДавайте создадим систему преобразования температуры с использованием паттерна Adapter. У вас есть legacy-датчик температуры, который выдаёт показания в Fahrenheit, но ваше современное weather application expects все температуры в Celsius. Вместо изменения любой из систем вы создадите адаптер, который устранит этот разрыв.
Вы организуете код в четырёх файлах:
TemperatureSensor.php: Define интерфейсTemperatureSensor, который ожидает ваше weather application. У него должен быть methodgetTemperature(): float, возвращающий температуру в Celsius.LegacySensor.php: CreateLegacySensorclass, имитирующий old оборудование. У этого class другой интерфейс, чем тот, который нужен вашему application:- Он принимает показание в Fahrenheit в своём constructor (используйте продвижение свойств constructor)
- У него есть method
readFahrenheit(): float, возвращающий сохранённое значение Fahrenheit
LegacySensorAdapter.php: Подключите интерфейс TemperatureSensor и class LegacySensor. Create classLegacySensorAdapter, который implementsTemperatureSensorи оборачиваетLegacySensor. Ваш адаптер должен:- Accept
LegacySensorв своём constructor - Implement
getTemperature(), считывая значение Fahrenheit с legacy-датчика и преобразуя его в Celsius по formula:(fahrenheit - 32) * 5 / 9
- Accept
main.php: Подключите файл LegacySensorAdapter. Вы получите один input: температуру в Fahrenheit.Create
LegacySensorс входной температурой, затем оберните его вLegacySensorAdapter. CallgetTemperature()у адаптера и выведите результат, округлённый до двух знаков после запятой.Формат Output должен быть таким:
Temperature: [celsius]C
Этот challenge демонстрирует, как паттерн Adapter позволяет интегрировать incompatible интерфейсы без изменения существующего кода. Ваше weather application работает исключительно с интерфейсом TemperatureSensor, совершенно не зная, что фактические показания поступают от legacy-датчика Fahrenheit.
Попробуйте сами
<?php
require_once 'LegacySensorAdapter.php';
// Прочитать ввод
$fahrenheit = floatval(trim(fgets(STDIN)));
// TODO: Создать LegacySensor с входной температурой
// TODO: Обернуть его в LegacySensorAdapter
// TODO: Вызвать getTemperature() на адаптере
// TODO: Вывести результат, округлённый до двух знаков после запятой
// Формат вывода: Temperature: [celsius]C
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Повторение — простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыПовторение — иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateМодификаторы доступа подробноГеттеры и сеттерыСокрытие информацииПродвижение конструктора (8.0)Повторение — система учёта студентов10Продвинутые концепции ООП
Композиция и наследованиеВнедрение зависимостейАнонимные классыПеречисления (PHP 8.1)Файберы (PHP 8.1)Глубокое погружение в клонирование объектовГенераторы и итераторы13Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Репозиторий»2Пространства имён и автозагрузка
Введение в пространства имёнКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerПовторение — структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс и абстрактный классАннотация типов с интерфейсамиПовторение — калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeПовторение — пользовательская коллекция3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищённые свойстваСвойства только для чтения (PHP 8.1)Повторение — менеджер банковского счёта6Полиморфизм
Повторение переопределения методовПолиморфизм через интерфейсыАннотации типов и объединённые типыПозднее статическое связываниеПовторение — обработчик платежей9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования, часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн StrategyПотренируйтесь самостоятельно: Онлайн-компилятор PHP