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

Как работает декоратор?

2.0 Middle🔥 121 комментариев
#SOLID и паттерны проектирования

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

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

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

Как работает декоратор (паттерн Decorator)

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

Принцип работы

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

// Интерфейс, который будут реализовывать компонент и декораторы
public interface Coffee {
    double getPrice();
    String getDescription();
}

// Базовый компонент
public class SimpleCoffee implements Coffee {
    @Override
    public double getPrice() {
        return 2.0;
    }
    
    @Override
    public String getDescription() {
        return "Простой кофе";
    }
}

// Абстрактный декоратор
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

// Конкретные декораторы
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public double getPrice() {
        return coffee.getPrice() + 0.5;
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", молоко";
    }
}

public class CaramelDecorator extends CoffeeDecorator {
    public CaramelDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public double getPrice() {
        return coffee.getPrice() + 0.75;
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", карамель";
    }
}

Использование

// Создаем простой кофе
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getDescription()); // "Простой кофе"
System.out.println(coffee.getPrice());        // 2.0

// Добавляем молоко
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription()); // "Простой кофе, молоко"
System.out.println(coffee.getPrice());        // 2.5

// Добавляем карамель
coffee = new CaramelDecorator(coffee);
System.out.println(coffee.getDescription()); // "Простой кофе, молоко, карамель"
System.out.println(coffee.getPrice());        // 3.25

Реальные примеры в Java

1. I/O потоки (классический пример)

FileInputStream fis = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);

// dis оборачивает bis, который оборачивает fis
// Каждый слой добавляет функциональность

2. Spring Framework

@Configuration
public class CacheConfig {
    @Bean
    public UserService userService(UserRepository repo, CacheManager cache) {
        return new CachedUserService(new UserServiceImpl(repo), cache);
    }
}

3. Аннотации в Java (как декораторы метаданных)

@Transactional
@Cacheable("users")
@Validated
public User getUser(Long id) {
    // Метод украшен аннотациями, которые добавляют функциональность
}

Преимущества и недостатки

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

  • Гибкость — можно комбинировать декораторы в любом порядке
  • Расширяемость — добавлять новые функции без изменения исходного класса
  • Альтернатива наследованию — избегаем explosion of classes
  • Соответствие SRP — каждый класс отвечает за одну функцию

Недостатки:

  • Усложнение кода — большое количество мелких классов
  • Сложность отладки — много слоев оборачивания
  • Порядок декораторов может быть важен

Отличие от наследования

Декоратор предпочтительнее наследования, когда нужна динамическая комбинация функций:

// ❌ Наследование ведет к explosion of classes
class CoffeeWithMilk extends SimpleCoffee { }
class CoffeeWithMilkAndCaramel extends CoffeeWithMilk { }
class CoffeeWithCaramel extends SimpleCoffee { }
// ... и комбинаций становится экспоненциально много

// ✅ Декоратор — гибкое решение
Coffee coffee = new CaramelDecorator(new MilkDecorator(new SimpleCoffee()));

Декоратор — это мощный паттерн для расширения функциональности без модификации исходного кода.

Как работает декоратор? | PrepBro