Что такое паттерн адаптер java
Перейти к содержимому

Что такое паттерн адаптер java

  • автор:

Адаптер на Java

Адаптер

Адаптер — это структурный паттерн, который позволяет подружить несовместимые объекты.

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

Сложность:

Популярность:

Применимость: Паттерн можно часто встретить в Java-коде, особенно там, где требуется конвертация разных типов данных или совместная работа классов с разными интерфейсами.

Примеры Адаптеров в стандартных библиотеках Java:

  • java.util.Arrays#asList()
  • java.util.Collections#list()
  • java.util.Collections#enumeration()
  • java.io.InputStreamReader(InputStream) (возвращает объект Reader )
  • java.io.OutputStreamWriter(OutputStream) (возвращает объект Writer )
  • javax.xml.bind.annotation.adapters.XmlAdapter#marshal() и #unmarshal()

Признаки применения паттерна: Адаптер получает конвертируемый объект в конструкторе или через параметры своих методов. Методы Адаптера обычно совместимы с интерфейсом одного объекта. Они делегируют вызовы вложенному объекту, превратив перед этим параметры вызова в формат, поддерживаемый вложенным объектом.

Помещение квадратных колышков в круглые отверстия

Этот простой пример показывает как с помощью паттерна Адаптер можно совмещать несовместимые вещи.

round

round/RoundHole.java: Круглое отверстие
package refactoring_guru.adapter.example.round; /** * КруглоеОтверстие совместимо с КруглымиКолышками. */ public class RoundHole < private double radius; public RoundHole(double radius) < this.radius = radius; >public double getRadius() < return radius; >public boolean fits(RoundPeg peg) < boolean result; result = (this.getRadius() >= peg.getRadius()); return result; > >
round/RoundPeg.java: Круглый колышек
package refactoring_guru.adapter.example.round; /** * КруглыеКолышки совместимы с КруглымиОтверстиями. */ public class RoundPeg < private double radius; public RoundPeg() <>public RoundPeg(double radius) < this.radius = radius; >public double getRadius() < return radius; >>

square

square/SquarePeg.java: Квадратный колышек
package refactoring_guru.adapter.example.square; /** * КвадратныеКолышки несовместимы с КруглымиОтверстиями (они остались в проекте * после бывших разработчиков). Но мы должны как-то интегрировать их в нашу * систему. */ public class SquarePeg < private double width; public SquarePeg(double width) < this.width = width; >public double getWidth() < return width; >public double getSquare() < double result; result = Math.pow(this.width, 2); return result; >>

adapters

adapters/SquarePegAdapter.java: Адаптер квадратных колышков к круглым отверстиям
package refactoring_guru.adapter.example.adapters; import refactoring_guru.adapter.example.round.RoundPeg; import refactoring_guru.adapter.example.square.SquarePeg; /** * Адаптер позволяет использовать КвадратныеКолышки и КруглыеОтверстия вместе. */ public class SquarePegAdapter extends RoundPeg < private SquarePeg peg; public SquarePegAdapter(SquarePeg peg) < this.peg = peg; >@Override public double getRadius() < double result; // Рассчитываем минимальный радиус, в который пролезет этот колышек. result = (Math.sqrt(Math.pow((peg.getWidth() / 2), 2) * 2)); return result; >>
Demo.java: Клиентский код
package refactoring_guru.adapter.example; import refactoring_guru.adapter.example.adapters.SquarePegAdapter; import refactoring_guru.adapter.example.round.RoundHole; import refactoring_guru.adapter.example.round.RoundPeg; import refactoring_guru.adapter.example.square.SquarePeg; /** * Где-то в клиентском коде. */ public class Demo < public static void main(String[] args) < // Круглое к круглому — всё работает. RoundHole hole = new RoundHole(5); RoundPeg rpeg = new RoundPeg(5); if (hole.fits(rpeg)) < System.out.println("Round peg r5 fits round hole r5."); >SquarePeg smallSqPeg = new SquarePeg(2); SquarePeg largeSqPeg = new SquarePeg(20); // hole.fits(smallSqPeg); // Не скомпилируется. // Адаптер решит проблему. SquarePegAdapter smallSqPegAdapter = new SquarePegAdapter(smallSqPeg); SquarePegAdapter largeSqPegAdapter = new SquarePegAdapter(largeSqPeg); if (hole.fits(smallSqPegAdapter)) < System.out.println("Square peg w2 fits round hole r5."); >if (!hole.fits(largeSqPegAdapter)) < System.out.println("Square peg w20 does not fit into round hole r5."); >> >
OutputDemo.txt: Результат выполнения
Round peg r5 fits round hole r5. Square peg w2 fits round hole r5. Square peg w20 does not fit into round hole r5.

Адаптер на других языках программирования

Купи книгу Погружение в Паттерны и получи архив с десятками детальных примеров, которые можно открывать прямо в IDE.

Refactoring.Guru

  • Премиум контент
    • Книга о паттернах
    • Курс по рефакторингу
    • Введение в рефакторинг
      • Чистый код
      • Технический долг
      • Когда рефакторить
      • Как рефакторить
      • Раздувальщики
        • Длинный метод
        • Большой класс
        • Одержимость элементарными типами
        • Длинный список параметров
        • Группы данных
        • Операторы switch
        • Временное поле
        • Отказ от наследства
        • Альтернативные классы с разными интерфейсами
        • Расходящиеся модификации
        • Стрельба дробью
        • Параллельные иерархии наследования
        • Комментарии
        • Дублирование кода
        • Ленивый класс
        • Класс данных
        • Мёртвый код
        • Теоретическая общность
        • Завистливые функции
        • Неуместная близость
        • Цепочка вызовов
        • Посредник
        • Неполнота библиотечного класса
        • Составление методов
          • Извлечение метода
          • Встраивание метода
          • Извлечение переменной
          • Встраивание переменной
          • Замена переменной вызовом метода
          • Расщепление переменной
          • Удаление присваиваний параметрам
          • Замена метода объектом методов
          • Замена алгоритма
          • Перемещение метода
          • Перемещение поля
          • Извлечение класса
          • Встраивание класса
          • Сокрытие делегирования
          • Удаление посредника
          • Введение внешнего метода
          • Введение локального расширения
          • Самоинкапсуляция поля
          • Замена простого поля объектом
          • Замена значения ссылкой
          • Замена ссылки значением
          • Замена поля-массива объектом
          • Дублирование видимых данных
          • Замена однонаправленной связи двунаправленной
          • Замена двунаправленной связи однонаправленной
          • Замена магического числа символьной константой
          • Инкапсуляция поля
          • Инкапсуляция коллекции
          • Замена кодирования типа классом
          • Замена кодирования типа подклассами
          • Замена кодирования типа состоянием/стратегией
          • Замена подкласса полями
          • Разбиение условного оператора
          • Объединение условных операторов
          • Объединение дублирующихся фрагментов в условных операторах
          • Удаление управляющего флага
          • Замена вложенных условных операторов граничным оператором
          • Замена условного оператора полиморфизмом
          • Введение Null-объекта
          • Введение проверки утверждения
          • Переименование метода
          • Добавление параметра
          • Удаление параметра
          • Разделение запроса и модификатора
          • Параметризация метода
          • Замена параметра набором специализированных методов
          • Передача всего объекта
          • Замена параметра вызовом метода
          • Замена параметров объектом
          • Удаление сеттера
          • Сокрытие метода
          • Замена конструктора фабричным методом
          • Замена кода ошибки исключением
          • Замена исключения проверкой условия
          • Подъём поля
          • Подъём метода
          • Подъём тела конструктора
          • Спуск метода
          • Спуск поля
          • Извлечение подкласса
          • Извлечение суперкласса
          • Извлечение интерфейса
          • Свёртывание иерархии
          • Создание шаблонного метода
          • Замена наследования делегированием
          • Замена делегирования наследованием
          • Введение в паттерны
            • Что такое Паттерн?
            • История паттернов
            • Зачем знать паттерны?
            • Критика паттернов
            • Классификация паттернов
            • Фабричный метод
            • Абстрактная фабрика
            • Строитель
            • Прототип
            • Одиночка
            • Адаптер
            • Мост
            • Компоновщик
            • Декоратор
            • Фасад
            • Легковес
            • Заместитель
            • Цепочка обязанностей
            • Команда
            • Итератор
            • Посредник
            • Снимок
            • Наблюдатель
            • Состояние
            • Стратегия
            • Шаблонный метод
            • Посетитель
            • C#
            • C++
            • Go
            • Java
            • PHP
            • Python
            • Ruby
            • Rust
            • Swift
            • TypeScript

            Структурные шаблоны проектирования: Adapter

            В структурных шаблонах проектирования рассматривается вопрос о том, каким образом из классов и объектов формируются более крупные структуры. Иными словами, структурные шаблоны, как правило, связаны с композицией объектов и с тем, как именно сущности могут использовать друг друга. По сути, они помогают узнать ответ на вопрос «Как создать программный компонент?» Один из таких шаблонов — «Адаптер» (Adapter).

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

            Давайте представим, что на карте памяти существуют фотографии, которые мы хотим перенести на наш ПК. Чтобы выполнить данную задачу, понадобится некий адаптер, совместимый с портами персонального компьютера. К примеру, пусть адаптером будет карт-ридер. Или же давайте вспомним ситуацию, когда в обычную розетку советских времен нельзя было вставить вилку, в простонародье именуемую «евро». Проблема решалась как установкой новых розеток, соответствующих евростандарту, так и более простым способом, который заключался в применении простейшего переходника. Ну и в качестве более понятного примера можно привести опытного переводчика, который обеспечивает коммуникацию между двумя людьми, не понимающими друг друга без посторонней помощи.

            Таким образом, шаблон «Адаптер» дает возможность оборачивать несовместимые объекты в адаптер с целью сделать их совместимыми с другим классом.

            Как это выглядит в коде

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

            Поначалу у нас есть интерфейс Lion, реализующий всех львов:

            1-1801-b6cde5.png

            На любую реализацию Lion-интерфейса охотится Hunter:

            2-1801-ed063d.png

            Теперь представьте, что надо добавить в игру WildDog, чтобы Hunter _смог охотиться и на нее. Но сделать это напрямую нельзя, ведь _WildDog — это другой интерфейс. Для обеспечения совместимости нам и пригодится адаптер:

            3-1801-530ceb.png

            Осталось рассмотреть способ применения:

            Java Blog

            Паттерн Адаптер (Adapter), также известный как Обертка (Wrapper), является структурным (Structural) паттерном проектирования. Его цель преобразовать интерфейс класса в другой интерфейс, который ожидают клиенты. Адаптер позволяет классам работать вместе, что иначе невозможно из-за несовместимых интерфейсов.

            Примеры из реального мира:

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

            Проще говоря паттерн адаптер позволяет обернуть несовместимый в противном случае объект в адаптер, чтобы сделать его совместимым с другим классом.

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

            Используйте паттерн адаптер, когда:

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

            Существует интерфейс Road

            public interface Road

            Класс Runner принимает и использует классы, реализующие интерфейс Road

            public class Runner < private Road road; public Runner()<>public Runner(Road road) < this.road = road; >public void runOnTheRoad() < System.out.println("Let's run"); road.run(); System.out.println("Finish"); >>

            Существует класс IceRoad, который не реализует интерфейс Road, но нам требуется использовать его в качестве Road

            public class IceRoad < void walk() < System.out.println("Someone walk on the ice road"); >; >

            Создаем класс адаптер IceRoadAdapter, реализующий интерфейс Road, но содержащий внутри класс IceRoad.

            public class IceRoadAdapter implements Road < private IceRoad road; public IceRoadAdapter() < road = new IceRoad(); >public void run() < road.walk(); >>

            Используем класс адаптер IceRoadAdapter для класса Runner.

            public class App < public static void main(String[] args)< Runner runner = new Runner(new IceRoadAdapter()); runner.runOnTheRoad(); >>

            Java. Adapter Pattern in Game Server

            Adapter

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

            Также известен как “Обертка”.

            Проблема

            Чтобы продемонстрировать этот шаблон, я буду использовать упрощенный пример игровой механики, в которой есть интерфейс IEnemy, но один из врагов отличается от других и не имеет реализации метода атаки. Вместо этого, этот конкретный враг (SpecialEnemy) накладывает заклинания.

            Решение

            Вы можете создать адаптер. Это специальный объект, который преобразует интерфейс одного объекта, чтобы другой объект мог его понять. Адаптер оборачивает один из объектов, чтобы скрыть сложность преобразования, происходящего за кулисами. Обернутый объект даже не знает об адаптере. Например, вы можете обернуть объект, который работает в метрах и километрах, с помощью адаптера, который преобразует все данные в британские единицы, такие как футы и мили. Адаптеры могут не только преобразовывать данные в различные форматы, но также могут помогать объектам с разными интерфейсами взаимодействовать друг с другом. Вот как это работает:

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

            Иногда даже можно создать двусторонний адаптер, который может конвертировать вызовы в обоих направлениях. Вернемся к нашему игровому приложению. Чтобы решить дилемму несовместимых врагов, вы можете создать адаптер EnemyAdapter для каждого класса особенных врагов, с которым ваш код работает напрямую. Затем вы настраиваете свой код для связи с SpecialEnemy только через эти адаптеры. Когда адаптер получает вызов, он переводит входящие атаки в кастование спеллов.

            Структура

            Существует несколько видов адаптеров

            Object adapter

            В этой реализации используется принцип композиции объектов: адаптер реализует интерфейс одного объекта и обертывает другой. Его можно реализовать на всех популярных языках программирования.

            Class adapter

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

            Применимость

            Используйте класс Adapter, если вы хотите использовать какой-либо существующий класс, но его интерфейс несовместим с остальной частью вашего кода.

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

            Используйте шаблон, если вы хотите повторно использовать несколько существующих подклассов, в которых отсутствуют некоторые общие функции и нельзя добавить в суперкласс.

            Вы можете расширить каждый подкласс и добавить недостающие функции в новые дочерние классы. Однако вам придется продублировать код во всех этих новых классах, что очень плохо «пахнет».

            Гораздо более элегантным решением было бы поместить недостающие функции в класс адаптера. Затем вы должны обернуть объекты с недостающими функциями внутри адаптера, динамически получая необходимые функции. Чтобы это работало, целевые классы должны иметь общий интерфейс, а поле адаптера должно следовать за этим интерфейсом. Этот подход очень похож на шаблон Decorator.

            Реализация

            Добавляем специальных врагов.

            Создадим класс SpecialEnemy, использующий метод CastSpell.

            class SpecialEnemy < public String castSpell() < return "using spell"; >>

            Я буду использовать строку возврата, чтобы упростить процесс.

            Затем, создадим интерфейс IEnemy для управления поведением врагов, в данном случае это только один метод для атаки

            interface IEnemy

            Теперь нам нужно реализовать этот интерфейс в классе EnemyAdapter, который соединит обе части вместе.

            class EnemyAdapter implements IEnemy < SpecialEnemy e = new SpecialEnemy(); public string attack() < return e.CastSpell(); >>

            Нам нужно добавить ссылку на SpecialEnemy, чтобы иметь доступ к методу CastSpell. Таким образом, мы можем использовать метод атаки без реализации его в SpecialEnemy. Или мы можем создать конструктор и передать туда экземпляр SpecialEnemy.

            class EnemyAdapter implements IEnemy < SpecialEnemy e; EnemyAdapter(SpecialEnemy se) < this.e = se; >public string attack() < return e.CastSpell(); >>

            Последний шаг — вызвать метод Enemy Attack в клиентском классе.

            class Main < public static void main(String[] args) < IEnemy enemy = new EnemyAdapter(); System.out.println(enemy.Attack()); >>

            В качестве вывода мы получаем строку «использование заклинания». Этот пример был слишком упрощен, но он демонстрирует идею, лежащую в основе этого простого шаблона. Надеюсь, он вам понравился и был полезен.

Добавить комментарий

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