← Назад к вопросам
Что такое паттерн Адаптер (Adapter)?
2.0 Middle🔥 121 комментариев
#SOLID и паттерны проектирования
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Паттерн Адаптер (Adapter Pattern)
Адаптер — это структурный паттерн проектирования, который позволяет работать с несовместимыми интерфейсами, преобразуя интерфейс одного класса в интерфейс, который ожидает клиент. Это как переходник для электрических вилок разных стран.
Основная проблема
Представьте ситуацию:
- У вас есть готовый класс
PayPalPaymentServiceс методомpayWithPayPal(amount) - Ваше приложение ожидает интерфейс
PaymentProcessorс методомprocess(amount) - Вы не можете изменить ни один из них
Решение: создать адаптер, который переводит один интерфейс в другой.
Структурные компоненты
Client → Target Interface ← Adapter ← Adaptee (несовместимый класс)
- Client — клиентский код
- Target Interface — интерфейс, который ожидает клиент
- Adapter — переходник между интерфейсами
- Adaptee — существующий класс с несовместимым интерфейсом
Два типа Адаптера
1. Адаптер на основе наследования (Class Adapter)
// Несовместимый интерфейс (Adaptee)
class OldPaymentSystem {
public String makePayment(double amount) {
return "Платеж на сумму " + amount + " рублей обработан";
}
}
// Целевой интерфейс (Target)
interface NewPaymentProcessor {
void processPayment(double amount);
}
// Адаптер (наследование)
class PaymentAdapter extends OldPaymentSystem implements NewPaymentProcessor {
@Override
public void processPayment(double amount) {
String result = makePayment(amount); // Используем старый метод
System.out.println(result);
}
}
// Использование
public class Main {
public static void main(String[] args) {
NewPaymentProcessor processor = new PaymentAdapter();
processor.processPayment(1000.0); // Работает!
}
}
2. Адаптер на основе композиции (Object Adapter) — рекомендуется
// Несовместимый интерфейс (Adaptee)
class PayPalService {
public void sendPayment(double amount, String email) {
System.out.println("PayPal платеж: " + amount + " на " + email);
}
}
// Целевой интерфейс (Target)
interface PaymentGateway {
void pay(double amount);
}
// Адаптер (композиция)
class PayPalAdapter implements PaymentGateway {
private PayPalService payPalService;
private String userEmail;
public PayPalAdapter(PayPalService service, String email) {
this.payPalService = service;
this.userEmail = email;
}
@Override
public void pay(double amount) {
payPalService.sendPayment(amount, userEmail);
}
}
// Использование
public class CheckoutService {
private PaymentGateway gateway;
public CheckoutService(PaymentGateway gateway) {
this.gateway = gateway;
}
public void checkout(double amount) {
gateway.pay(amount);
}
public static void main(String[] args) {
PayPalService paypal = new PayPalService();
PaymentGateway adapter = new PayPalAdapter(paypal, "user@example.com");
CheckoutService checkout = new CheckoutService(adapter);
checkout.checkout(500.0); // Работает!
}
}
Практические примеры из реальной жизни
Пример 1: Интеграция различных логирующих систем
// Старая система логирования (Adaptee)
class LegacyLogger {
public void writeLog(String message, int level) {
System.out.println("[LEVEL " + level + "] " + message);
}
}
// Новый интерфейс (Target)
interface ModernLogger {
void info(String message);
void error(String message);
void debug(String message);
}
// Адаптер
class LoggerAdapter implements ModernLogger {
private LegacyLogger legacyLogger;
public LoggerAdapter(LegacyLogger logger) {
this.legacyLogger = logger;
}
@Override
public void info(String message) {
legacyLogger.writeLog(message, 1); // Info = level 1
}
@Override
public void error(String message) {
legacyLogger.writeLog(message, 3); // Error = level 3
}
@Override
public void debug(String message) {
legacyLogger.writeLog(message, 0); // Debug = level 0
}
}
Пример 2: Работа с различными БД
// Несовместимые интерфейсы
class MySQLDatabase {
public ResultSet executeQuery(String sql) {
System.out.println("Выполнение MySQL запроса: " + sql);
return null;
}
}
class MongoDBDatabase {
public Document findOne(String collection, Map<String, Object> filter) {
System.out.println("Поиск в MongoDB коллекции: " + collection);
return null;
}
}
// Единый интерфейс
interface Database {
Object executeQuery(String query);
}
// Адаптеры
class MySQLAdapter implements Database {
private MySQLDatabase mysql;
public MySQLAdapter(MySQLDatabase db) {
this.mysql = db;
}
@Override
public Object executeQuery(String query) {
return mysql.executeQuery(query);
}
}
class MongoDBAdapter implements Database {
private MongoDBDatabase mongodb;
public MongoDBAdapter(MongoDBDatabase db) {
this.mongodb = db;
}
@Override
public Object executeQuery(String query) {
// Парсим query и преобразуем в MongoDB операцию
return mongodb.findOne("users", new HashMap<>());
}
}
// Использование
class DataRepository {
private Database database;
public DataRepository(Database db) {
this.database = db;
}
public Object getUsers() {
return database.executeQuery("SELECT * FROM users");
}
}
Пример 3: Адаптация коллекций
Java использует Adapter паттерн внутри:
// Arrays.asList() - адаптирует array в List
String[] array = {"a", "b", "c"};
List<String> list = Arrays.asList(array); // Адаптер!
// Collections.list() - адаптирует Enumeration в List
Enumeration<String> enumeration = Collections.enumeration(list);
List<String> adapted = Collections.list(enumeration); // Адаптер!
Когда использовать Adapter?
✅ Используй, когда:
- Нужно использовать класс с несовместимым интерфейсом
- Хочешь обеспечить совместимость между несколькими системами
- Нужно переиспользовать старый код в новой архитектуре
- Интегрируешь сторонние библиотеки
❌ Не используй, если:
- Можно изменить интерфейс оригинального класса
- Паттерн усложняет код без необходимости
- Лучше подходит другой паттерн (Facade, Proxy)
Адаптер vs другие паттерны
| Паттерн | Назначение | Когда использовать |
|---|---|---|
| Adapter | Переводит интерфейсы | Несовместимые интерфейсы |
| Facade | Упрощает интерфейс | Сложная подсистема |
| Proxy | Контролирует доступ | Нужна ленивая загрузка, проверка |
| Decorator | Добавляет функциональность | Динамическое расширение |
Преимущества и недостатки
✅ Преимущества:
- Позволяет использовать несовместимый код
- Разделяет интерфейс клиента от реализации
- Улучшает переиспользуемость кода
- Изолирует от изменений внешних систем
❌ Недостатки:
- Добавляет дополнительные классы
- Может усложнить отладку
- Может повлиять на производительность
Выводы: Adapter — это мощный паттерн для интеграции несовместимых систем. Он особенно полезен при работе с наследственным кодом и сторонними библиотеками. Выбирай композицию вместо наследования (Object Adapter) для большей гибкости.