Паттерн декоратор используется для изменения функциональности объекта во время выполнения. В то же время другие экземпляры того же класса не будут затронуты этим, поэтому каждый отдельный объект получает измененное поведение. Паттерн декоратора является одним из структурных паттернов проектирования (таких как Паттерн адаптера, Паттерн моста, Паттерн компоновщика) и использует абстрактные классы или интерфейсы с композицией для реализации.
Паттерн декоратора
Мы используем наследование или композицию для расширения поведения объекта, но это происходит на этапе компиляции и применимо ко всем экземплярам класса. Мы не можем добавлять новую функциональность или удалять существующее поведение во время выполнения – здесь на помощь приходит паттерн Декоратор. Предположим, мы хотим реализовать разные виды автомобилей – мы можем создать интерфейс Car для определения метода assemble, а затем у нас может быть базовый автомобиль, который далее можно расширить до спортивного автомобиля и роскошного автомобиля. Иерархия реализации будет выглядеть как на картинке ниже. Но если мы хотим получить автомобиль во время выполнения, который имеет и спортивные, и роскошные характеристики, то реализация становится сложной, а если мы хотим указать, какие функции должны быть добавлены первыми, она становится еще более сложной. Теперь представьте, что у нас есть десять разных видов автомобилей, логика реализации с использованием наследования и композиции будет невозможна для управления. Чтобы решить эту проблему программирования, мы применяем паттерн Декоратор в Java. Мы должны иметь следующие типы для реализации паттерна декоратора.
-
Интерфейс компонента – Интерфейс или абстрактный класс, определяющий методы, которые будут реализованы. В нашем случае
Car
будет интерфейсом компонента.package com.journaldev.design.decorator; public interface Car { public void assemble(); }
-
Реализация компонента – Основная реализация интерфейса компонента. Мы можем иметь класс
BasicCar
как нашу реализацию компонента.package com.journaldev.design.decorator; public class BasicCar implements Car { @Override public void assemble() { System.out.print("Basic Car."); } }
-
Декоратор – класс Декоратор реализует интерфейс компонента и имеет отношение HAS-A с интерфейсом компонента. Переменная компонента должна быть доступна для дочерних классов декоратора, поэтому мы сделаем эту переменную защищенной.
package com.journaldev.design.decorator; public class CarDecorator implements Car { protected Car car; public CarDecorator(Car c){ this.car=c; } @Override public void assemble() { this.car.assemble(); } }
-
Конкретные Декораторы – Расширение базовой функциональности декоратора и изменение поведения компонента соответственно. Мы можем иметь конкретные классы декораторов, такие как
LuxuryCar
иSportsCar
.package com.journaldev.design.decorator; public class SportsCar extends CarDecorator { public SportsCar(Car c) { super(c); } @Override public void assemble(){ super.assemble(); System.out.print(" Добавление функций спортивного автомобиля."); } }
package com.journaldev.design.decorator; public class LuxuryCar extends CarDecorator { public LuxuryCar(Car c) { super(c); } @Override public void assemble(){ super.assemble(); System.out.print(" Добавление функций роскошного автомобиля."); } }
Диаграмма классов паттерна декоратор
Тестовая программа для паттерна декоратор
package com.journaldev.design.test;
import com.journaldev.design.decorator.BasicCar;
import com.journaldev.design.decorator.Car;
import com.journaldev.design.decorator.LuxuryCar;
import com.journaldev.design.decorator.SportsCar;
public class DecoratorPatternTest {
public static void main(String[] args) {
Car sportsCar = new SportsCar(new BasicCar());
sportsCar.assemble();
System.out.println("\n*****");
Car sportsLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar()));
sportsLuxuryCar.assemble();
}
}
Обратите внимание, что клиентская программа может создавать различные виды объектов во время выполнения, и они также могут указывать порядок выполнения. Вывод вышеуказанной тестовой программы:
Basic Car. Adding features of Sports Car.
*****
Basic Car. Adding features of Luxury Car. Adding features of Sports Car.
Важные моменты паттерна декоратор
- Паттерн декоратора полезен для обеспечения возможностей изменения во время выполнения и, следовательно, более гибкий. Легко поддерживать и расширять, когда количество вариантов больше.
- Недостатком паттерна декоратора является то, что он использует много похожих объектов (декораторов).
- Шаблон декоратора часто используется в классах Java IO, таких как FileReader, BufferedReader и т. д.
Source:
https://www.digitalocean.com/community/tutorials/decorator-design-pattern-in-java-example