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

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

2.0 Middle🔥 141 комментариев
#Архитектура и микросервисы#ООП и паттерны проектирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

📘 Паттерн Адаптер (Adapter) в C#

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


🎯 Основная цель

Главная задача адаптера — обеспечить совместную работу классов, которые без него не могли бы взаимодействовать из-за несовпадения интерфейсов. Это достигается без изменения исходного кода адаптируемых классов, следуя принципу Open/Closed (открытости/закрытости).


🔧 Типы адаптеров

В C# адаптер может быть реализован двумя основными способами:

1. Адаптер на основе наследования (Class Adapter)

Использует наследование от адаптируемого класса и реализацию целевого интерфейса. Это требует множественного наследования, которое в C# не поддерживается напрямую, но может быть эмулировано через наследование класса и реализацию интерфейса.

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

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

// Адаптер, наследуемый от Adaptee и реализующий ITarget
public class Adapter : Adaptee, ITarget
{
    public string GetRequest()
    {
        // Преобразуем вызов GetRequest() в GetSpecificRequest()
        return $"Adapter: {base.GetSpecificRequest()}";
    }
}

2. Адаптер на основе композиции (Object Adapter)

Использует композицию: адаптер содержит экземпляр адаптируемого класса и делегирует ему вызовы. Этот подход более гибкий и соответствует принципу Composition over Inheritance.

public class Adapter : ITarget
{
    private readonly Adaptee _adaptee;

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

    public string GetRequest()
    {
        // Адаптер преобразует интерфейс
        return $"Adapter: {_adaptee.GetSpecificRequest()}";
    }
}

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

Рассмотрим практический сценарий: интеграция старой системы логирования с новой, где интерфейсы не совпадают.

// Новый интерфейс логирования
public interface ILogger
{
    void Log(string message);
}

// Старый класс логирования (несовместимый интерфейс)
public class LegacyLogger
{
    public void LogMessage(string text)
    {
        Console.WriteLine($"Legacy: {text}");
    }
}

// Адаптер для старого логировщика
public class LoggerAdapter : ILogger
{
    private LegacyLogger _legacyLogger = new LegacyLogger();

    public void Log(string message)
    {
        _legacyLogger.LogMessage($"[Adapted] {message}");
    }
}

// Клиентский код работает только с ILogger
public class Application
{
    private ILogger _logger;

    public Application(ILogger logger) => _logger = logger;

    public void Run()
    {
        _logger.Log("Приложение запущено.");
    }
}

// Использование
var legacyLogger = new LegacyLogger();
var adapter = new LoggerAdapter(legacyLogger);
var app = new Application(adapter);
app.Run();

✅ Преимущества паттерна Адаптер

  • Совместимость: Позволяет интегрировать классы с несовместимыми интерфейсами.
  • Принцип единой ответственности: Отделяет преобразование интерфейса от основной логики.
  • Гибкость: Можно добавлять новые адаптеры без изменения клиентского кода.
  • Reusability: Повторное использование существующих классов в новых системах.

⚠️ Недостатки

  • Усложнение кода: Введение дополнительных классов может увеличить сложность.
  • Непрямой вызов: Клиент работает через промежуточный слой, что может затруднить отладку.

💡 Когда использовать адаптер?

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

🔄 Сравнение с другими паттернами

  • Мост (Bridge) разделяет абстракцию и реализацию, тогда как Адаптер изменяет интерфейс существующего объекта.
  • Декоратор (Decorator) добавляет новые обязанности, не меняя интерфейса, а Адаптер именно преобразует интерфейс.
  • Фасад (Facade) предоставляет упрощённый интерфейс к сложной подсистеме, а Адаптер делает конкретный класс совместимым с определённым интерфейсом.

🧠 Заключение

Паттерн Адаптер — это мощный инструмент для обеспечения взаимодействия между компонентами с несовместимыми интерфейсами. В C# он чаще реализуется через композицию (Object Adapter) из-за ограничений множественного наследования. Использование адаптера позволяет соблюдать принципы SOLID, особенно принцип открытости/закрытости, и способствует созданию гибкого, поддерживаемого кода. Однако важно не злоупотреблять им, чтобы не превратить систему в набор «костылей» — адаптер должен применяться там, где действительно необходим мост между несовместимыми интерфейсами.

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