Menu
Coddy logo textTech

Паттерн Адаптер

Часть раздела Объектно-ориентированное программирование путешествия по 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, когда хотите использовать существующий класс, но его интерфейс не соответствует тому, что вам нужно, или когда вам необходимо создать повторно используемый класс, который взаимодействует с классами, имеющими несовместимые интерфейсы.

challenge icon

Задание

Легко

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

Вы создадите два файла, чтобы организовать реализацию шаблона адаптера:

  • 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() на вашем источнике аудио и выведите результат
  
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Dart