Что такое паттерн проектирования «Прокси» (Proxy)?

Ответ

Прокси (Proxy) — это структурный паттерн, который предоставляет объект-заместитель или placeholder для другого объекта, контролируя доступ к нему. Прокси и реальный объект имеют одинаковый интерфейс, что позволяет клиенту работать с прокси так, как будто это реальный объект.

Зачем он нужен? Чтобы добавить дополнительный уровень косвенности для управления доступом, кэширования, логгирования, отложенной инициализации или защиты реального объекта.

Основные типы прокси:

  1. Виртуальный прокси (Lazy Initialization): Создает дорогой объект только по требованию.
  2. Защищающий прокси (Protection Proxy): Контролирует доступ к объекту на основе прав.
  3. Прокси удаленного доступа (Remote Proxy): Представляет объект, находящийся в другом адресном пространстве.
  4. Прокси для логирования/кэширования: Добавляет сквозную функциональность.

Пример на Java (Виртуальный прокси для тяжелого изображения):

// 1. Общий интерфейс
interface Image {
    void display();
}

// 2. Реальный объект (дорогой в создании)
class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(); // Долгая операция
    }

    private void loadFromDisk() {
        System.out.println("Loading image: " + filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}

// 3. Прокси-заместитель
class ProxyImage implements Image {
    private RealImage realImage; // Ссылка на реальный объект
    private String filename;

    public ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        // Ленивая загрузка: создаем реальный объект только при первом вызове
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

// 4. Использование
public class Main {
    public static void main(String[] args) {
        Image image = new ProxyImage("high_res_photo.jpg");
        // RealImage еще НЕ создан

        System.out.println("Image object created. RealImage not loaded yet.");

        image.display(); // Первый вызов загружает и показывает
        // Loading image: high_res_photo.jpg
        // Displaying image: high_res_photo.jpg

        image.display(); // Второй вызов использует уже загруженный объект
        // Displaying image: high_res_photo.jpg
    }
}

Ключевые преимущества:

  • Контролируемый доступ. Можно добавить проверки до вызова реального объекта.
  • Ленивая инициализация. Откладывает создание ресурсоемких объектов.
  • Дополнительная логика. Легко добавить кэширование, логирование, безопасность.
  • Прозрачность для клиента. Клиентский код работает с интерфейсом, не зная о прокси.

Реализация в Java: Механизм динамических прокси (java.lang.reflect.Proxy) часто используется в AOP (Aspect-Oriented Programming) и фреймворках вроде Spring.

Ответ 18+ 🔞

А, паттерн Прокси! Ну это ж классика, блядь, как Герасим с Муму, только в мире кода. Сейчас объясню на пальцах, а то ты, сука, опять будешь делать вид, что понял, а сам нихуя.

Представь, ты — важный чувак, типа олигарх. К тебе на приём всякие просители ломятся. Но ты что, будешь каждого мудака с улицы к себе в кабинет пускать? Нихуя! У тебя есть секретарша — вот она и есть твой прокси, ёпта! Она имеет тот же интерфейс, что и ты: «принять посетителя». Но она сначала фильтрует: одного пошлёт нахуй, другому скажет «барин спит», а только действительно важного клиента — вот тогда уже и пропустит к тебе, реальному объекту. Прозрачно же, блядь! Клиент думает, что общается с тобой, а на самом деле его уже три раза обматерили на ресепшене.

Зачем эта хуйня? Да чтобы жизнь малиной не казалась! Иногда реальный объект — это такой здоровенный татарин, как Герасим, создавать его — овердохуища ресурсов. А иногда к нему просто так пускать нельзя — он у тебя в другом дата-центре, или ты хочешь всё, что к нему обращаются, записывать, как в протокол. Вот прокси и впендюривается между клиентом и реальной штукой, делает всю грязную работу.

Какие они бывают, эти прокси-мудаки:

  1. Виртуальный (Ленивый). Это когда твой «Герасим» — здоровенный, в натуре, файл на 10 гигов. Загружать его сразу — пиздец как долго. А прокси говорит: «Да не, я пока постою тут картинкой-заглушкой, а как реально понадобится — вот тогда, сука, и загружусь». Лень — двигатель прогресса, блядь!
  2. Защищающий. Секьюрити на входе в клуб. «Ты кто такой? У тебя есть @Role("ADMIN")? Нет? Иди нахуй, полупидор». Прямо как княгиня, которая Муму топила.
  3. Удалённый. Вообще охуеть! Реальный объект сидит на другом сервере, за тридевять земель. А прокси тут, локально, делает вид, что это он. А сам потихоньку шлёт запросы по сети. Магия, блядь, ебать мои старые костыли.
  4. Для логирования/кэширования. Хитрый такой. Пропускает все вызовы к реальному объекту, но по пути тихонько записывает в журнал: «В 14:35 Вася вызвал метод transferMoney(100500)». Или, если результат уже знает, из своей хитрой жопы (кэша) его достаёт, чтобы реальный объект не ебал мозги.

Смотри, как это в коде выглядит, на примере ленивой картинки:

// 1. Интерфейс, который все должны соблюдать. Как договор, блядь.
interface Image {
    void display();
}

// 2. Реальная, тяжёлая картинка. Её создание — это пиздец какой долгий процесс.
class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(); // Вот эта хуйня может грузиться секунд 10!
    }

    private void loadFromDisk() {
        System.out.println("Loading image: " + filename + " (сижу, гружусь, блядь...)");
    }

    @Override
    public void display() {
        System.out.println("Displaying image: " + filename + " (вот я, смотри!)");
    }
}

// 3. Прокси-обманщик. Он легковесный, создаётся мгновенно.
class ProxyImage implements Image {
    private RealImage realImage; // Ссылка на того самого Герасима, но пока её нет!
    private String filename;

    public ProxyImage(String filename) {
        this.filename = filename;
        System.out.println("Proxy created for: " + filename + " (я просто бумажка, меня не грузить)");
    }

    @Override
    public void display() {
        // А вот тут магия! Если реального объекта нет — создаём его. ЛЕНИВО, БЛЯДЬ!
        if (realImage == null) {
            realImage = new RealImage(filename); // Опа, только сейчас пошла долгая загрузка!
        }
        realImage.display(); // А теперь делегируем вызов реальной тяжёлой хрени.
    }
}

// 4. Как этим пользоваться
public class Main {
    public static void main(String[] args) {
        // Создаём прокси — это быстро и безболезненно
        Image image = new ProxyImage("high_res_photo.jpg");
        // В консоли: "Proxy created for: high_res_photo.jpg"
        // RealImage ещё НЕ создан! Его не грузили! Мы молодцы.

        System.out.println("nА теперь, сука, потребуем показать картинку...");
        image.display(); // ПЕРВЫЙ вызов! Прокси понимает, что пора.
        // В консоли: "Loading image: high_res_photo.jpg (сижу, гружусь, блядь...)"
        // Потом: "Displaying image: high_res_photo.jpg (вот я, смотри!)"

        System.out.println("nПоказываем ещё разок...");
        image.display(); // ВТОРОЙ вызов! А реальный объект УЖЕ загружен.
        // В консоли ТОЛЬКО: "Displaying image: high_res_photo.jpg (вот я, смотри!)"
        // Загрузки больше не будет! Прокси просто передаст вызов готовому объекту.
        // Экономия — мать ебёной пизды!
    }
}

Итоги, блядь:

  • Контроль доступа — как секретарша-стерва.
  • Ленивая инициализация — не грузим тяжёлое, пока не приспичило.
  • Дополнительная логика — можно прикрутить логирование, кэш, безопасность, не трогая сам реальный объект. Это же, блядь, принцип единственной ответственности в действии!
  • Прозрачность — клиенту похуй, с кем он работает. Интерфейс-то один.

В Java, кстати, есть целая банда готовых прокси-головорезов — java.lang.reflect.Proxy. Их Spring, например, использует, чтобы налетать на твои бины и навешивать на них транзакции или логирование. Красота, ёпта! В рот меня чих-пых, как же это удобно.