Приведи пример паттерна Proxy на Java.

«Приведи пример паттерна Proxy на Java.» — вопрос из категории Паттерны, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Паттерн Proxy (Заместитель) предоставляет суррогатный объект, контролирующий доступ к другому объекту. Основные типы: удаленный, виртуальный, защищающий, логирующий.

Пример защищающего прокси (Protection Proxy):

  1. Общий интерфейс:

    public interface DatabaseAccess {
    void query(String sql) throws AccessDeniedException;
    }
  2. Реальный объект:

    public class RealDatabaseAccess implements DatabaseAccess {
    @Override
    public void query(String sql) {
        System.out.println("Executing query: " + sql);
        // Реальная логика выполнения запроса к БД
    }
    }
  3. Прокси-объект (добавляет контроль доступа):

    public class DatabaseAccessProxy implements DatabaseAccess {
    private RealDatabaseAccess realService;
    private String userRole;
    
    public DatabaseAccessProxy(String userRole) {
        this.userRole = userRole;
    }
    
    @Override
    public void query(String sql) throws AccessDeniedException {
        // Дополнительная логика ПЕРЕД вызовом реального объекта
        if (!"ADMIN".equals(userRole)) {
            throw new AccessDeniedException("User '" + userRole + "' cannot execute queries.");
        }
        // Ленивая инициализация реального объекта
        if (realService == null) {
            realService = new RealDatabaseAccess();
        }
        // Делегирование вызова реальному объекту
        realService.query(sql);
        // Здесь можно добавить логику ПОСЛЕ вызова (логирование, кэширование)
        System.out.println("Query executed by: " + userRole);
    }
    }
  4. Использование клиентом:

    public class Client {
    public static void main(String[] args) {
        DatabaseAccess adminAccess = new DatabaseAccessProxy("ADMIN");
        try {
            adminAccess.query("DELETE FROM users"); // Успешно
        } catch (AccessDeniedException e) {
            e.printStackTrace();
        }
    
        DatabaseAccess userAccess = new DatabaseAccessProxy("USER");
        try {
            userAccess.query("SELECT * FROM users"); // Выбросит AccessDeniedException
        } catch (AccessDeniedException e) {
            System.out.println("Expected error: " + e.getMessage());
        }
    }
    }

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

  • Контроль доступа: Прокси проверяет права перед выполнением операции.
  • Ленивая инициализация (Виртуальный прокси): Ресурсоемкий объект создается только при необходимости.
  • Дополнительная функциональность: Легко добавить логирование, кэширование, управление соединениями без изменения реального объекта.