Home » Шаблон декоратор в Java — пример и урок
Шаблон декоратор в Java — пример и урок

Шаблон декоратор в 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 поможет сделать твою серверную архитектуру более гибкой и масштабируемой!


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

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

Leave a reply

Your email address will not be published. Required fields are marked