Приведи пример паттерна Proxy на 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());
        }
    }
    }

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

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

Ответ 18+ 🔞

А, паттерн Proxy, блядь! Это ж как будто ты нанимаешь себе секретаря-хулигана, который стоит перед дверью и решает, кого пускать к тебе, а кому дать пизды. Заместитель, сука, в натуре!

Смотри, в чём прикол. Есть у тебя какой-то важный объект — база данных, тяжёлый сервис, файловая система, ёпта. И ты не хочешь, чтобы к нему лезли все подряд, как в публичный сортир. Вот тут и появляется этот самый прокси — такой здоровый буфер между клиентом и реальной штукой.

Основные разновидности, блядь:

  • Удалённый (Remote): Когда реальный объект сидит на другом сервере, а прокси притворяется, что он тут, рядом, и просто пересылает запросы туда-сюда. Как курьер, блядь.
  • Виртуальный (Virtual): Ленивая жопа! Не создаёт тяжёлый объект, пока реально не понадобится. «А, тебе картинку? Ща, бля, только загружу... ой, а она весит овердохуища гигабайт».
  • Защищающий (Protection): Вот это наш случай, блядь! Стоит как вышибала в клубе и проверяет паспорт: «Ты кто такой? Админ? Проходи. Юзер? Иди нахуй, отсоси у тракториста».
  • Логирующий (Logging): Стоит и всё записывает в блокнотик: «Вася в 12:05 пытался удалить всю базу, пидарас шерстяной».

Вот тебе пример, как этот защищающий вышибала работает:

  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()); // «Так и знал, что не пустят»
        }
    }
    }

И в чём же, блядь, кайф?

  • Контроль доступа: Прокси решает, кто достоин, а кто — манда с ушами. Безопасность, ёпта!
  • Ленивая инициализация: Не грузим память и процессор, пока реально не надо. Экономия, блядь!
  • Дополнительная функциональность: Хочешь логировать, кэшировать, замерять время — делай это в прокси, не трогая священный реальный объект. Чистота кода, сука!

Вот и весь паттерн. Не заместитель, а такой управдом, который всем заправляет. Удобная хуйня, если использовать с умом.