- Home »

Шаблон декоратор в Java — пример и урок
Привет, админы и серверные джедаи! Сегодня разберём паттерн Decorator в Java — штуку, которая может серьёзно упростить архитектуру твоих серверных приложений. Если ты когда-нибудь писал логгеры для мониторинга серверов, системы кеширования для веб-приложений или просто хотел добавить функциональность к объектам без изменения их кода — этот паттерн для тебя. Особенно полезен при разработке middleware компонентов для серверных решений, где нужно динамически добавлять обработку запросов, шифрование, сжатие данных и другие фичи.
Как работает паттерн Decorator
Decorator позволяет добавлять новую функциональность объектам, оборачивая их в полезные “обёртки”. Представь, что у тебя есть базовый HTTP-сервер, и ты хочешь добавить к нему логирование, аутентификацию, сжатие — всё это можно сделать через декораторы, не трогая основной код.
Основные компоненты:
- Component — интерфейс для объектов, которые могут получить дополнительные обязанности
- ConcreteComponent — класс объектов, к которым добавляется новая функциональность
- Decorator — абстрактный класс, который содержит ссылку на объект Component
- ConcreteDecorator — конкретные декораторы, добавляющие функциональность
Пошаговая реализация для серверных задач
Давай создадим систему обработки HTTP-запросов с декораторами. Это частая задача при настройке серверов и middleware.
Шаг 1: Создаём базовый интерфейс
public interface HttpHandler {
String handleRequest(String request);
}
Шаг 2: Базовый обработчик запросов
public class BasicHttpHandler implements HttpHandler {
@Override
public String handleRequest(String request) {
return "Processed: " + request;
}
}
Шаг 3: Абстрактный декоратор
public abstract class HttpHandlerDecorator implements HttpHandler {
protected HttpHandler handler;
public HttpHandlerDecorator(HttpHandler handler) {
this.handler = handler;
}
@Override
public String handleRequest(String request) {
return handler.handleRequest(request);
}
}
Шаг 4: Конкретные декораторы для серверных нужд
// Декоратор для логирования
public class LoggingDecorator extends HttpHandlerDecorator {
public LoggingDecorator(HttpHandler handler) {
super(handler);
}
@Override
public String handleRequest(String request) {
System.out.println("[LOG] Request received: " + request);
String result = super.handleRequest(request);
System.out.println("[LOG] Response sent: " + result);
return result;
}
}
// Декоратор для аутентификации
public class AuthenticationDecorator extends HttpHandlerDecorator {
public AuthenticationDecorator(HttpHandler handler) {
super(handler);
}
@Override
public String handleRequest(String request) {
if (!isAuthenticated(request)) {
return "ERROR: Authentication required";
}
return super.handleRequest(request);
}
private boolean isAuthenticated(String request) {
return request.contains("auth_token");
}
}
// Декоратор для сжатия данных
public class CompressionDecorator extends HttpHandlerDecorator {
public CompressionDecorator(HttpHandler handler) {
super(handler);
}
@Override
public String handleRequest(String request) {
String response = super.handleRequest(request);
return compress(response);
}
private String compress(String data) {
return "[COMPRESSED] " + data;
}
}
Шаг 5: Используем декораторы в действии
public class ServerExample {
public static void main(String[] args) {
// Базовый обработчик
HttpHandler handler = new BasicHttpHandler();
// Оборачиваем в декораторы
handler = new LoggingDecorator(handler);
handler = new AuthenticationDecorator(handler);
handler = new CompressionDecorator(handler);
// Обрабатываем запрос
String result = handler.handleRequest("GET /api/users auth_token=abc123");
System.out.println("Final result: " + result);
}
}
Практические примеры и кейсы
Положительный кейс: Мониторинг серверов
// Декоратор для метрик
public class MetricsDecorator extends HttpHandlerDecorator {
private static final Map requestCount = new ConcurrentHashMap<>();
public MetricsDecorator(HttpHandler handler) {
super(handler);
}
@Override
public String handleRequest(String request) {
long startTime = System.currentTimeMillis();
// Увеличиваем счётчик запросов
requestCount.merge(getEndpoint(request), 1, Integer::sum);
String result = super.handleRequest(request);
long duration = System.currentTimeMillis() - startTime;
System.out.println("[METRICS] Endpoint: " + getEndpoint(request) +
", Duration: " + duration + "ms");
return result;
}
private String getEndpoint(String request) {
return request.split(" ")[1];
}
public static void printStats() {
System.out.println("=== REQUEST STATISTICS ===");
requestCount.forEach((endpoint, count) ->
System.out.println(endpoint + ": " + count + " requests"));
}
}
Отрицательный кейс: Избыточное использование декораторов может создать глубокую цепочку вызовов и усложнить отладку. Не стоит создавать более 5-7 уровней декораторов.
Критерий | Decorator | Inheritance | Composition |
---|---|---|---|
Гибкость | Высокая | Низкая | Средняя |
Сложность отладки | Средняя | Низкая | Низкая |
Производительность | Средняя | Высокая | Высокая |
Расширяемость | Отличная | Плохая | Хорошая |
Интеграция с популярными серверными фреймворками
Decorator отлично работает с Spring Boot и другими фреймворками:
@Component
public class CacheDecorator extends HttpHandlerDecorator {
private final RedisTemplate redisTemplate;
public CacheDecorator(HttpHandler handler, RedisTemplate redisTemplate) {
super(handler);
this.redisTemplate = redisTemplate;
}
@Override
public String handleRequest(String request) {
String cacheKey = generateCacheKey(request);
String cached = redisTemplate.opsForValue().get(cacheKey);
if (cached != null) {
return cached;
}
String result = super.handleRequest(request);
redisTemplate.opsForValue().set(cacheKey, result, Duration.ofMinutes(5));
return result;
}
private String generateCacheKey(String request) {
return "request:" + request.hashCode();
}
}
Автоматизация и скрипты
Decorator можно использовать для создания гибких систем развёртывания. Например, декораторы для Docker-контейнеров:
// Декоратор для мониторинга контейнеров
public class ContainerMonitoringDecorator extends HttpHandlerDecorator {
private final DockerClient dockerClient;
public ContainerMonitoringDecorator(HttpHandler handler, DockerClient dockerClient) {
super(handler);
this.dockerClient = dockerClient;
}
@Override
public String handleRequest(String request) {
checkContainerHealth();
return super.handleRequest(request);
}
private void checkContainerHealth() {
try {
List containers = dockerClient.listContainersCmd().exec();
containers.forEach(container -> {
if (!"running".equals(container.getState())) {
System.err.println("Container " + container.getId() + " is not running!");
}
});
} catch (Exception e) {
System.err.println("Failed to check container health: " + e.getMessage());
}
}
}
Альтернативные решения и сравнение
Есть несколько альтернатив Decorator паттерну:
- Proxy Pattern — больше подходит для контроля доступа
- Chain of Responsibility — для последовательной обработки
- Strategy Pattern — для выбора алгоритма
- AOP (Aspect-Oriented Programming) — для кроссрежущей функциональности
Для серверных приложений также стоит рассмотреть:
- Netflix Hystrix — для Circuit Breaker паттерна
- Resilience4j — современная альтернатива Hystrix
- Micrometer — для метрик и мониторинга
Интересные факты и нестандартные применения
Decorator активно используется в:
- Java I/O API — BufferedReader, FileReader и т.д.
- Spring Security — цепочка фильтров безопасности
- Servlet API — HttpServletRequestWrapper
- Netty — ChannelHandler pipeline
Нестандартное применение — создание декораторов для SSH-команд:
public class SSHCommandDecorator extends HttpHandlerDecorator {
private final JSch jsch;
private final String host;
private final String user;
public SSHCommandDecorator(HttpHandler handler, String host, String user) {
super(handler);
this.jsch = new JSch();
this.host = host;
this.user = user;
}
@Override
public String handleRequest(String request) {
if (request.startsWith("ssh:")) {
return executeSSHCommand(request.substring(4));
}
return super.handleRequest(request);
}
private String executeSSHCommand(String command) {
// Выполнение SSH команды
// Полезно для удалённого управления серверами
return "SSH result: " + command;
}
}
Развёртывание на VPS и выделенных серверах
При работе с серверными приложениями, использующими Decorator, важно учесть:
- Память: Каждый декоратор создаёт дополнительный объект
- Производительность: Глубокая цепочка вызовов может замедлить работу
- Логирование: Нужно правильно настроить трассировку через декораторы
Для продуктивной работы рекомендую VPS с достаточным объёмом RAM (минимум 2GB для Java-приложений) или выделенный сервер для высоконагруженных систем.
Заключение и рекомендации
Decorator — мощный паттерн для серверной разработки, который даёт:
- Гибкость: Можно комбинировать функциональность как конструктор
- Расширяемость: Добавление новых фич без изменения существующего кода
- Переиспользование: Декораторы можно применять к разным объектам
- Тестируемость: Каждый декоратор можно тестировать отдельно
Используй Decorator когда:
- Нужно добавить функциональность без изменения кода
- Требуется гибкая комбинация возможностей
- Работаешь с middleware компонентами
- Создаёшь системы мониторинга и логирования
Избегай когда:
- Простое наследование решает задачу
- Производительность критична
- Цепочка декораторов становится слишком глубокой
Помни: хороший код — это не только рабочий код, но и поддерживаемый. Decorator поможет сделать твою серверную архитектуру более гибкой и масштабируемой!
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.