← Назад к вопросам

Приведи пример использования паттерна адаптер

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 систем с современным кодом.