← Назад к вопросам
Приведи пример использования паттерна адаптер
2.0 Middle🔥 161 комментариев
#SOLID и паттерны проектирования
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерн Adapter (Адаптер)
Adapter — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать друг с другом. Адаптер преобразует интерфейс одного класса в интерфейс, который ожидает клиент.
Классическая задача
Представьте, что у вас есть старая система (legacy code) с одним интерфейсом, а новая система ожидает другой. Нужно их объединить без переписывания кода.
Пример 1: Интеграция платёжных систем
// Старая система платежей (legacy)
public interface OldPaymentSystem {
void processPayment(double amount, String account);
void refund(double amount, String account);
}
// Новая система ожидает другой интерфейс
public interface PaymentGateway {
PaymentResult pay(PaymentRequest request);
RefundResult refund(RefundRequest request);
}
// Данные для новой системы
public class PaymentRequest {
private BigDecimal amount;
private String currency;
private String paymentMethod;
private String description;
// getters
}
public class PaymentResult {
private boolean success;
private String transactionId;
private String message;
// getters
}
Теперь создаём адаптер:
public class PaymentSystemAdapter implements PaymentGateway {
private OldPaymentSystem oldSystem;
public PaymentSystemAdapter(OldPaymentSystem oldSystem) {
this.oldSystem = oldSystem;
}
@Override
public PaymentResult pay(PaymentRequest request) {
try {
// Преобразуем новый формат в старый
String account = extractAccount(request);
double amount = request.getAmount().doubleValue();
// Вызываем старую систему
oldSystem.processPayment(amount, account);
// Преобразуем результат в новый формат
return new PaymentResult(
true,
generateTransactionId(),
"Payment processed successfully"
);
} catch (Exception e) {
return new PaymentResult(
false,
null,
"Payment failed: " + e.getMessage()
);
}
}
@Override
public RefundResult refund(RefundRequest request) {
try {
String account = extractAccount(request);
double amount = request.getAmount().doubleValue();
oldSystem.refund(amount, account);
return new RefundResult(true, "Refund processed");
} catch (Exception e) {
return new RefundResult(false, "Refund failed: " + e.getMessage());
}
}
private String extractAccount(PaymentRequest request) {
// Логика преобразования
return request.getPaymentMethod();
}
private String extractAccount(RefundRequest request) {
return request.getPaymentMethod();
}
private String generateTransactionId() {
return UUID.randomUUID().toString();
}
}
Теперь новый код работает с новым интерфейсом:
public class CheckoutService {
private PaymentGateway paymentGateway;
public CheckoutService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
public Order checkout(Cart cart) {
PaymentRequest request = new PaymentRequest(
cart.getTotal(),
"USD",
"credit_card",
"Order #123"
);
PaymentResult result = paymentGateway.pay(request);
if (result.isSuccess()) {
return createOrder(cart, result.getTransactionId());
} else {
throw new PaymentException(result.getMessage());
}
}
}
// Использование:
public class Main {
public static void main(String[] args) {
// Старая система
OldPaymentSystem oldSystem = new StripeOldAPI();
// Адаптируем к новому интерфейсу
PaymentGateway gateway = new PaymentSystemAdapter(oldSystem);
// Новый код использует новый интерфейс
CheckoutService checkout = new CheckoutService(gateway);
Order order = checkout.checkout(new Cart());
}
}
Пример 2: Адаптация Collection к List
// Старый код с Vector (наследник Collection)
Vector<String> oldVector = new Vector<>();
oldVector.add("item1");
oldVector.add("item2");
// Новый код ожидает List
List<String> list = new ArrayList<>(oldVector);
// или
List<String> list = Collections.list(oldVector.elements());
Пример 3: Адаптация JSON к Object
// Старая библиотека JSON парсера
public class OldJsonParser {
public String[] parseArray(String json) {
// Возвращает массив строк
return json.split(",");
}
}
// Новая система ожидает списки объектов
public interface DataLoader {
List<DataPoint> loadData(String json);
}
// Адаптер
public class JsonParserAdapter implements DataLoader {
private OldJsonParser parser;
public JsonParserAdapter(OldJsonParser parser) {
this.parser = parser;
}
@Override
public List<DataPoint> loadData(String json) {
String[] items = parser.parseArray(json);
return Arrays.stream(items)
.map(item -> new DataPoint(item.trim()))
.collect(Collectors.toList());
}
}
Пример 4: Адаптация Iterator к Stream
// Старый код возвращает Iterator
public class OldDataRepository {
public Iterator<User> getUsers() {
return new ArrayList<>(loadUsersFromDB()).iterator();
}
}
// Новый код ожидает Stream
public interface UserProvider {
Stream<User> streamUsers();
}
// Адаптер
public class IteratorToStreamAdapter implements UserProvider {
private OldDataRepository repository;
public IteratorToStreamAdapter(OldDataRepository repository) {
this.repository = repository;
}
@Override
public Stream<User> streamUsers() {
Iterator<User> iterator = repository.getUsers();
Spliterator<User> spliterator = Spliterators.spliteratorUnknownSize(
iterator,
Spliterator.ORDERED
);
return StreamSupport.stream(spliterator, false);
}
}
Диаграмма паттерна
┌─────────────┐ ┌──────────────────┐
│ Client │-------->│ Target Interface│
│ (новый) │ └──────────────────┘
└─────────────┘ △
│ реализует
┌──────────────┐
│ Adapter │
└──────────────┘
│
использует
│
▼
┌──────────────────┐
│ Adaptee │
│ (старый класс) │
└──────────────────┘
Два типа адаптеров
1. Class Adapter (наследование)
public class ClassAdapter extends OldPaymentSystem implements PaymentGateway {
@Override
public PaymentResult pay(PaymentRequest request) {
// Вызывает методы родительского класса (OldPaymentSystem)
this.processPayment(request.getAmount().doubleValue(),
request.getPaymentMethod());
return new PaymentResult(true, "OK");
}
}
2. Object Adapter (композиция)
public class ObjectAdapter implements PaymentGateway {
private OldPaymentSystem adaptee; // Композиция!
public ObjectAdapter(OldPaymentSystem adaptee) {
this.adaptee = adaptee;
}
@Override
public PaymentResult pay(PaymentRequest request) {
adaptee.processPayment(...);
return new PaymentResult(true, "OK");
}
}
Когда использовать Adapter
✅ Используй:
- Интеграция legacy систем с новым кодом
- Работа с третьей стороной библиотеками
- Реализация совместимости между несовместимыми интерфейсами
- Обёртка над external API
❌ Избегай:
- Если можно просто изменить интерфейс
- Если это делает код более сложным
- Вместо рефакторинга старого кода
Преимущества и недостатки
Преимущества:
- Позволяет использовать несовместимые интерфейсы
- Разделяет ответственность (Single Responsibility)
- Гибкость при интеграции
Недостатки:
- Добавляет слой сложности
- Может снизить производительность (дополнительная обёртка)
- Может затруднить отладку
Adapter — это спасение для интеграции legacy систем с современным кодом.