Паттерн Адаптер
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy. Урок 95 из 110.
Паттерн Adapter позволяет несовместимым интерфейсам работать вместе. Он действует как мост между двумя классами, которые иначе не смогли бы взаимодействовать, оборачивая существующий класс новым интерфейсом, которого ожидают клиенты. Это особенно полезно при интеграции сторонних библиотек или устаревшего кода в ваше приложение.
Представьте, что у вас есть система, которая работает с данными JSON, но вам нужно интегрировать компонент, который выводит только XML. Вместо изменения любого из этих class вы создаёте adapter, который переводит данные между ними:
// Существующий интерфейс, который ожидает ваша система
abstract class JsonData {
String getJson();
}
// Устаревший класс с несовместимым интерфейсом
class XmlService {
String getXml() {
return '<data><name>John</name></data>';
}
}
// Адаптер делает XmlService совместимым с JsonData
class XmlToJsonAdapter implements JsonData {
final XmlService _xmlService;
XmlToJsonAdapter(this._xmlService);
@override
String getJson() {
String xml = _xmlService.getXml();
// Преобразовать XML в JSON (упрощённо)
return '{"name": "John"}';
}
}
void main() {
var xmlService = XmlService();
var adapter = XmlToJsonAdapter(xmlService);
print(adapter.getJson()); // {"name": "John"}
}XmlToJsonAdapter оборачивает XmlService и реализует интерфейс JsonData. Клиентский код работает со знакомым интерфейсом JsonData, не зная, что исходно данные поступили из источника XML. Адаптер выполняет всё преобразование внутри себя.
Используйте паттерн Adapter, когда хотите использовать существующий класс, но его интерфейс не соответствует тому, что вам нужно, или когда вам необходимо создать повторно используемый класс, который взаимодействует с классами, имеющими несовместимые интерфейсы.
Задание
ЛегкоДавайте создадим систему адаптера медиаплеера! Представьте, что у вас есть современная аудиосистема, которая ожидает, что все источники мультимедиа будут предоставлять звук через стандартный интерфейс, но вам нужно интегрировать старомодный проигрыватель виниловых пластинок, использующий совершенно другой способ воспроизведения звука.
Вы создадите два файла, чтобы организовать реализацию шаблона адаптера:
media_adapter.dart: Этот файл содержит ваши интерфейс и классы адаптера. Определите абстрактный классAudioSource, который ожидает ваша современная система, — у него должен быть методString playAudio(), возвращающий аудиовыход в виде строки. Затем создайте классVinylPlayer, представляющий устаревшее оборудование, — у него есть полеtrackNameи методString spinRecord(), возвращающий*crackle* Playing vinyl: [trackName] *crackle*. Наконец, создайтеVinylAdapter, который реализуетAudioSourceи оборачиваетVinylPlayer. МетодplayAudio()адаптера должен вызывать методspinRecord()проигрывателя виниловых пластинок и возвращать результат, связывая несовместимые интерфейсы.main.dart: Импортируйте файл медиаадаптера и продемонстрируйте, как адаптер позволяет старому проигрывателю виниловых пластинок работать с кодом, который ожидает современный интерфейсAudioSource. СоздайтеVinylPlayerс названием композицииBohemian Rhapsody. Затем создайтеVinylAdapter, который оборачивает этот проигрыватель виниловых пластинок. Сохраните адаптер в переменной типаAudioSource, чтобы подтвердить его соответствие ожидаемому интерфейсу. ВызовитеplayAudio()для вашего аудиоисточника и выведите результат.
Преимущество этого шаблона в том, что ваш основной код работает со стандартным интерфейсом AudioSource — ему не нужно знать, что за кулисами фактическую работу выполняет старый проигрыватель виниловых пластинок!
Ожидаемый вывод:
*crackle* Playing vinyl: Bohemian Rhapsody *crackle*Попробуйте сами
import 'media_adapter.dart';
void main() {
// TODO: Создайте VinylPlayer с названием трека "Bohemian Rhapsody"
// TODO: Создайте VinylAdapter, который оборачивает виниловый проигрыватель
// TODO: Сохраните адаптер в переменной типа AudioSource
// TODO: Вызовите playAudio() на вашем источнике аудио и выведите результат
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн РепозиторийПотренируйтесь самостоятельно: Онлайн-компилятор Dart