6. Реализовать паттерн Decorator
Условие задачи:
Необходимо реализовать паттерн проектирования Decorator.
Декоратор должен позволять динамически добавлять объекту новое поведение без изменения его исходного класса.
Для примера реализуем обработку текстового сообщения:
базовое сообщение возвращает исходный текст;
один декоратор переводит текст в верхний регистр;
второй добавляет в конец восклицательные знаки;
декораторы можно комбинировать.
Спойлеры к решению
Подсказки
💡 Декоратор должен хранить ссылку на объект того же интерфейса.
💡 Базовый декоратор делегирует вызов обёрнутому объекту.
💡 Конкретные декораторы добавляют поведение до или после делегирования.
💡 Декораторы можно вкладывать друг в друга.
Решение
interface Message {
String getContent();
}
class SimpleMessage implements Message {
private final String content;
public SimpleMessage(String content) {
this.content = content;
}
@Override
public String getContent() {
return content;
}
}
abstract class MessageDecorator implements Message {
protected final Message delegate;
protected MessageDecorator(Message delegate) {
this.delegate = delegate;
}
@Override
public String getContent() {
return delegate.getContent();
}
}
class UppercaseDecorator extends MessageDecorator {
public UppercaseDecorator(Message delegate) {
super(delegate);
}
@Override
public String getContent() {
return super.getContent().toUpperCase();
}
}
class ExclamationDecorator extends MessageDecorator {
public ExclamationDecorator(Message delegate) {
super(delegate);
}
@Override
public String getContent() {
return super.getContent() + "!!!";
}
}
Использование:
Message message = new SimpleMessage("Hello");
message = new UppercaseDecorator(message);
message = new ExclamationDecorator(message);
System.out.println(message.getContent());
Результат:
HELLO!!!
Все компоненты реализуют один интерфейс:
interface Message {
String getContent();
}
Поэтому декоратор можно использовать везде, где ожидается обычный Message.
Базовый декоратор хранит обёрнутый объект:
protected final Message delegate;
и делегирует ему вызов:
return delegate.getContent();
Конкретный декоратор добавляет собственное поведение. Например:
return super.getContent().toUpperCase();
Декораторы можно комбинировать:
ExclamationDecorator
↓
UppercaseDecorator
↓
SimpleMessage
Главное преимущество паттерна — новое поведение можно добавлять и комбинировать без изменения класса SimpleMessage и без создания большого количества его наследников.