Java. Adapter Pattern in Game Server
Адаптер — это шаблон структурного проектирования, который позволяет объектам с несовместимыми интерфейсами взаимодействовать друг с другом.
Также известен как “Обертка”.
Проблема
Чтобы продемонстрировать этот шаблон, я буду использовать упрощенный пример игровой механики, в которой есть интерфейс IEnemy, но один из врагов отличается от других и не имеет реализации метода атаки. Вместо этого, этот конкретный враг (SpecialEnemy) накладывает заклинания.
Решение
Вы можете создать адаптер. Это специальный объект, который преобразует интерфейс одного объекта, чтобы другой объект мог его понять. Адаптер оборачивает один из объектов, чтобы скрыть сложность преобразования, происходящего за кулисами. Обернутый объект даже не знает об адаптере. Например, вы можете обернуть объект, который работает в метрах и километрах, с помощью адаптера, который преобразует все данные в британские единицы, такие как футы и мили. Адаптеры могут не только преобразовывать данные в различные форматы, но также могут помогать объектам с разными интерфейсами взаимодействовать друг с другом. Вот как это работает:
- Адаптер получает интерфейс, совместимый с одним из существующих объектов.
- Используя этот интерфейс, существующий объект может безопасно вызывать методы адаптера.
- При получении вызова адаптер передает запрос второму объекту, но в формате и порядке, которые ожидает второй объект.
Иногда даже можно создать двусторонний адаптер, который может конвертировать вызовы в обоих направлениях. Вернемся к нашему игровому приложению. Чтобы решить дилемму несовместимых врагов, вы можете создать адаптер 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()); >>
В качестве вывода мы получаем строку «использование заклинания». Этот пример был слишком упрощен, но он демонстрирует идею, лежащую в основе этого простого шаблона. Надеюсь, он вам понравился и был полезен.
Адаптер на 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.
- Премиум контент
- Книга о паттернах
- Курс по рефакторингу
- Введение в рефакторинг
- Чистый код
- Технический долг
- Когда рефакторить
- Как рефакторить
- Раздувальщики
- Длинный метод
- Большой класс
- Одержимость элементарными типами
- Длинный список параметров
- Группы данных
- Операторы switch
- Временное поле
- Отказ от наследства
- Альтернативные классы с разными интерфейсами
- Расходящиеся модификации
- Стрельба дробью
- Параллельные иерархии наследования
- Комментарии
- Дублирование кода
- Ленивый класс
- Класс данных
- Мёртвый код
- Теоретическая общность
- Завистливые функции
- Неуместная близость
- Цепочка вызовов
- Посредник
- Неполнота библиотечного класса
- Составление методов
- Извлечение метода
- Встраивание метода
- Извлечение переменной
- Встраивание переменной
- Замена переменной вызовом метода
- Расщепление переменной
- Удаление присваиваний параметрам
- Замена метода объектом методов
- Замена алгоритма
- Перемещение метода
- Перемещение поля
- Извлечение класса
- Встраивание класса
- Сокрытие делегирования
- Удаление посредника
- Введение внешнего метода
- Введение локального расширения
- Самоинкапсуляция поля
- Замена простого поля объектом
- Замена значения ссылкой
- Замена ссылки значением
- Замена поля-массива объектом
- Дублирование видимых данных
- Замена однонаправленной связи двунаправленной
- Замена двунаправленной связи однонаправленной
- Замена магического числа символьной константой
- Инкапсуляция поля
- Инкапсуляция коллекции
- Замена кодирования типа классом
- Замена кодирования типа подклассами
- Замена кодирования типа состоянием/стратегией
- Замена подкласса полями
- Разбиение условного оператора
- Объединение условных операторов
- Объединение дублирующихся фрагментов в условных операторах
- Удаление управляющего флага
- Замена вложенных условных операторов граничным оператором
- Замена условного оператора полиморфизмом
- Введение Null-объекта
- Введение проверки утверждения
- Переименование метода
- Добавление параметра
- Удаление параметра
- Разделение запроса и модификатора
- Параметризация метода
- Замена параметра набором специализированных методов
- Передача всего объекта
- Замена параметра вызовом метода
- Замена параметров объектом
- Удаление сеттера
- Сокрытие метода
- Замена конструктора фабричным методом
- Замена кода ошибки исключением
- Замена исключения проверкой условия
- Подъём поля
- Подъём метода
- Подъём тела конструктора
- Спуск метода
- Спуск поля
- Извлечение подкласса
- Извлечение суперкласса
- Извлечение интерфейса
- Свёртывание иерархии
- Создание шаблонного метода
- Замена наследования делегированием
- Замена делегирования наследованием
- Введение в паттерны
- Что такое Паттерн?
- История паттернов
- Зачем знать паттерны?
- Критика паттернов
- Классификация паттернов
- Фабричный метод
- Абстрактная фабрика
- Строитель
- Прототип
- Одиночка
- Адаптер
- Мост
- Компоновщик
- Декоратор
- Фасад
- Легковес
- Заместитель
- Цепочка обязанностей
- Команда
- Итератор
- Посредник
- Снимок
- Наблюдатель
- Состояние
- Стратегия
- Шаблонный метод
- Посетитель
- C#
- C++
- Go
- Java
- PHP
- Python
- Ruby
- Rust
- Swift
- TypeScript
Что такое паттерн адаптер java
13 июня 2022
Понравилось про кардридер и особенно про карту,которая лежит внутри кардридера. Просто идеальное сравнение.
Greatsky Уровень 37
28 декабря 2021
Не знаю кому — там что понятно – но 1) InputStream extends Object класс является абстрактным – есть методы читающие байты 2) Reader extends Object — является абстрактным – есть методы читающие символы 3) BufferedReader extends Reader класс не абстрактный, есть методы читающие символы 4) InputStreamReader extends Reader класс не абстрактный, есть методы читающие символы 5) класс System extends Object – со статической переменной System.in которая имеет тип InputStream – итого имеем: для чтения байт есть класс InputStream и методы, для чтения символов класс BufferedReader и методы, напрашивается вопрос на кой черт нужен InputStreamReader, может я не прав, но мне кажется не хватает тут везде фразы чтобы читать символы как минимум из консоли, а консоль это InputStream, а как максимум другие потоки которые все имеют почему ( я еще пока не знаю. наверное исторически сложилось ) тип именно InputStream, поэтому и нужен адаптер inputstreamreader ну и наверное что бы на основе потом сделали FileReader extends InputStreamReader, к тому же внутри класса InputStreamReader вовсе не вызываются методы переданного ему переменной потока (что логично), поэтому это адаптер будет посложнее обычного
«Почему бы и да» Уровень 33
Что такое паттерн адаптер java
Текст вылез за границы оформления кода. public class Middleware implements Excuse < // 1. Middleware становится совместимым с объектом WorkExcuse через интерфейс Excuse
Сообщество
JavaRush — это интерактивный онлайн-курс по изучению Java-программирования c нуля. Он содержит 1200 практических задач с проверкой решения в один клик, необходимый минимум теории по основам Java и мотивирующие фишки, которые помогут пройти курс до конца: игры, опросы, интересные проекты и статьи об эффективном обучении и карьере Java‑девелопера.
Подписывайтесь
Язык интерфейса
«Программистами не рождаются» © 2023 JavaRush
Скачивайте наши приложения
«Программистами не рождаются» © 2023 JavaRushЭтот веб-сайт использует данные cookie, чтобы настроить персонально под вас работу сервиса. Используя веб-сайт, вы даете согласие на применение данных cookie. Больше подробностей — в нашем Пользовательском соглашении.