Что такое паттерн Адаптер (Adapter)?

«Что такое паттерн Адаптер (Adapter)?» — вопрос из категории Паттерны, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Адаптер (Adapter) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли «переводчика» или «прослойки», преобразуя интерфейс одного класса в интерфейс, ожидаемый клиентом.

Аналогия из жизни: Это переходник для розетки, который позволяет вилке одного стандарта работать с розеткой другого.

Когда использовать:

  • Когда нужно использовать существующий класс, но его интерфейс не соответствует требованиям вашего кода.
  • Для интеграции сторонних библиотек или legacy-кода без изменения их исходного кода.
  • Когда нужно создать унифицированный интерфейс для нескольких классов с разными интерфейсами.

Реализация: Существует два основных типа адаптеров:

1. Адаптер на основе композиции (объектный адаптер) — предпочтительный способ.

// Целевой интерфейс, который ожидает клиентский код
public interface ITarget
{
    string GetRequest();
}

// Адаптируемый класс с «чужим» интерфейсом
public class Adaptee
{
    public string GetSpecificRequest()
    {
        return "Specific request from Adaptee.";
    }
}

// Адаптер: реализует целевой интерфейс и содержит ссылку на Adaptee
public class Adapter : ITarget
{
    private readonly Adaptee _adaptee;

    public Adapter(Adaptee adaptee)
    {
        _adaptee = adaptee;
    }

    public string GetRequest()
    {
        // Преобразование вызова GetRequest() в вызов GetSpecificRequest()
        return _adaptee.GetSpecificRequest();
    }
}

// Клиентский код работает только с интерфейсом ITarget
class Client
{
    static void Main()
    {
        Adaptee adaptee = new Adaptee();
        ITarget target = new Adapter(adaptee); // Обёртывание

        Console.WriteLine(target.GetRequest()); // Вывод: Specific request from Adaptee.
    }
}

2. Адаптер на основе наследования (классовый адаптер) — требует множественного наследования (недоступно в C#, но возможно в C++).

Преимущества:

  • Принцип единой ответственности: Отделяет код преобразования интерфейса от основной бизнес-логики.
  • Принцип открытости/закрытости: Позволяет вводить новые адаптеры, не ломая существующий клиентский код.
  • Повторное использование: Делает несовместимые классы пригодными для использования.

Недостатки:

  • Усложняет код, добавляя новые классы. Иногда проще изменить клиентский код, если это возможно.