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

В чем разница между паттерном декоратор и адаптер?

1.7 Middle🔥 131 комментариев
#ООП и паттерны проектирования

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

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

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

Разница между паттернами Декоратор и Адаптер

В объектно-ориентированном программировании Декоратор (Decorator) и Адаптер (Adapter) являются двумя классическими паттернами из категории структурных паттернов, но они решают совершенно разные задачи и имеют принципиально различные подходы к изменению поведения объектов.

Основная цель и задача

Декоратор предназначен для динамического добавления новых обязанностей или поведения к объекту, без изменения его исходной структуры или интерфейса. Это паттерн расширения функциональности.

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

Ключевые различия в реализации

1. Структурные особенности

Декоратор оборачивает объект, сохраняя его исходный интерфейс, но добавляет новые возможности. Адаптер изменяет интерфейс объекта, чтобы соответствовать ожиданиям клиента.

2. Сохранение интерфейса

// Декоратор сохраняет интерфейс
public interface IComponent
{
    void Operation();
}

public class ConcreteComponent : IComponent
{
    public void Operation() => Console.WriteLine("Базовая операция");
}

public class Decorator : IComponent
{
    private readonly IComponent _component;
    
    public Decorator(IComponent component) => _component = component;
    
    public void Operation()
    {
        _component.Operation(); // Вызываем оригинальный метод
        Console.WriteLine("Дополнительное поведение декоратора");
    }
}

// Использование декоратора
IComponent component = new ConcreteComponent();
IComponent decoratedComponent = new Decorator(component);
decoratedComponent.Operation(); // Интерфейс не изменен!
// Адаптер изменяет интерфейс
public interface ITarget
{
    void Request();
}

public class Adaptee
{
    public void SpecificRequest() => Console.WriteLine("Специфический метод Adaptee");
}

public class Adapter : ITarget
{
    private readonly Adaptee _adaptee;
    
    public Adapter(Adaptee adaptee) => _adaptee = adaptee;
    
    public void Request()
    {
        _adaptee.SpecificRequest(); // Адаптируем метод под новый интерфейс
    }
}

// Использование адаптера
Adaptee adaptee = new Adaptee();
ITarget adapter = new Adapter(adaptee);
adapter.Request(); // Клиент работает с новым интерфейсом

3. Динамичность vs Статичность

Декоратор часто применяется динамически - можно добавлять несколько декораторов последовательно, создавая "цепочку" расширений. Адаптер обычно применяется статически - создается один адаптер для решения проблемы совместимости.

4. Назначение объектов

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

Практические примеры применения

Декоратор в реальных сценариях

  • Добавление логирования к существующим методам без изменения бизнес-логики
  • Добавление кэширования к операциям чтения данных
  • Добавление валидации или безопасности к методам сервисов
  • Stream декораторы в .NET: BufferedStream, CryptoStream оборачивают базовые потоки
// Пример декоратора для кэширования
public interface IDataService
{
    string GetData(int id);
}

public class CachingDecorator : IDataService
{
    private readonly IDataService _service;
    private readonly Dictionary<int, string> _cache = new();
    
    public CachingDecorator(IDataService service) => _service = service;
    
    public string GetData(int id)
    {
        if (_cache.ContainsKey(id))
            return _cache[id];
        
        var data = _service.GetData(id);
        _cache[id] = data;
        return data;
    }
}

Адаптер в реальных сценариях

  • Интеграция сторонних библиотек с вашей системой
  • Адаптация старых классов к новым интерфейсам при рефакторинге
  • Работа с различными API платежных систем через единый интерфейс
  • ADO.NET адаптеры: SqlDataAdapter адаптирует данные SQL к объектам .NET

Сравнение в табличной форме

КритерийДекораторАдаптер
Основная цельРасширение функциональностиСовместимость интерфейсов
Изменение интерфейсаНе изменяетсяИзменяется полностью
Количество обертокМожет быть несколькоОбычно одна
Отношения классовОдна иерархияРазные иерархии
ДинамичностьВысокая (можно добавлять динамически)Статичная (решает конкретную проблему)
Влияние на клиентаКлиент не знает о декоратореКлиент знает только новый интерфейс

Когда выбирать каждый паттерн

Выбирайте Декоратор, когда:

  • Нужно расширить функциональность объекта без изменения его кода
  • Требуется добавлять возможности динамически в runtime
  • Необходимо сохранить оригинальный интерфейс для клиентов

Выбирайте Адаптер, когда:

  • Есть готовый класс с несовместимым интерфейсом
  • Нужно интегрировать стороннюю систему или библиотеку
  • Требуется унифицировать несколько разных интерфейсов под один

Итог

Основное философское отличие: Декоратор - это "надстройка" над объектом, которая усиливает его возможности, сохраняя его "личность" (интерфейс). Адаптер - это "переводчик" между объектами, который меняет "личность" объекта (интерфейс) для обеспечения взаимодействия с другим миром (системой). Декоратор работает с родственными объектами, адаптер - с иностранцами, которых нужно адаптировать к местным стандартам.