Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 71 из 87.

Шаблон Adapter — это структурный шаблон проектирования, который позволяет несовместимым интерфейсам работать вместе. Он действует как мост между двумя классами, преобразуя интерфейс одного класса в интерфейс, который ожидает Client. Представь его как адаптер питания, позволяющий подключить европейское устройство к американской розетке.

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

// Существующий интерфейс, который использует ваш код
interface MediaPlayer {
    void play(String filename);
}

// Сторонний класс с несовместимым интерфейсом
class AdvancedVideoPlayer {
    public void playVideo(String filename) {
        System.out.println("Playing video: " + filename);
    }
}

adapter оборачивает incompatible class и implements ожидаемый interface, преобразуя вызовы между ними:

class VideoPlayerAdapter implements MediaPlayer {
    private AdvancedVideoPlayer videoPlayer;
    
    public VideoPlayerAdapter() {
        this.videoPlayer = new AdvancedVideoPlayer();
    }
    
    public void play(String filename) {
        videoPlayer.playVideo(filename);
    }
}

Теперь ваш клиентский код может использовать видеоплеер через знакомый интерфейс MediaPlayer:

MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4");  // Вывод: Playing video: movie.mp4

Шаблон Adapter незаменим при интеграции legacy-кода или сторонних библиотек без изменения их исходного кода. Client не знает о том, что работает с адаптированным классом. Он просто использует известный ему интерфейс.

challenge icon

Задание

Легко

Давайте создадим систему преобразования температуры с использованием паттерна Adapter! У вас есть существующее погодное приложение, работающее с температурами в Celsius, но вам нужно интегрировать legacy-датчик температуры, который выдаёт показания только в Fahrenheit. Вместо изменения любой из систем вы создадите adapter, который устранит несовместимость между ними.

Вы организуете код в четырёх файлах:

  • TemperatureProvider.java: Define interface, которую ожидает ваше погодное приложение. Она должна Declare метод getTemperatureCelsius(), возвращающий double, представляющий температуру в Celsius.
  • FahrenheitSensor.java: Этот класс представляет legacy-датчик с incompatible interface. Create class с private double field для температуры в Fahrenheit, задаваемым через constructor. В нём должен быть метод readFahrenheit(), возвращающий сохранённое значение в Fahrenheit.
  • SensorAdapter.java: Create adapter, который делает FahrenheitSensor compatible с вашим погодным приложением. Ваш adapter должен implements TemperatureProvider и оборачивать FahrenheitSensor. При вызове getTemperatureCelsius() он должен считывать значение с датчика и convert его в Celsius по формуле: (fahrenheit - 32) * 5 / 9.
  • Main.java: Объедините всё вместе! Вы получите один input: показание температуры в Fahrenheit (double).

    Create FahrenheitSensor со значением из input. Затем Create SensorAdapter, который оборачивает этот датчик. Сохраните adapter в переменной типа TemperatureProvider, чтобы показать, что ваше погодное приложение может использовать его через ожидаемый interface.

    Выведите результат в таком формате: Temperature: [celsius] C, где celsius отформатирован с точностью до одного знака после десятичной точки.

Вы получите один input: температуру в Fahrenheit (double).

Например, для input 98.6 результатом будет:

Temperature: 37.0 C

Обратите внимание, что ваш Main class полностью работает с interface TemperatureProvider. Он не знает, что фактическая температура поступает от FahrenheitSensor, адаптированного за кулисами. В этом и заключается элегантность паттерна Adapter!

Попробуйте сами

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double fahrenheit = scanner.nextDouble();
        
        // TODO: Создайте FahrenheitSensor с входным значением
        
        // TODO: Создайте SensorAdapter, который оборачивает датчик
        
        // TODO: Сохраните адаптер в переменной TemperatureProvider
        
        // TODO: Получите температуру в градусах Цельсия и выведите её
        // Формат: "Temperature: [celsius] C" с одним знаком после запятой
        // Подсказка: Используйте String.format("%.1f", value) для форматирования
    }
}
quiz iconПроверьте себя

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

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

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