Что такое паттерн Прокси и приведи пример его использования?

Ответ

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

Пример: Ленивая загрузка (Lazy Loading) тяжелого объекта.

// 1. Общий интерфейс для реального объекта и прокси
interface ExpensiveService {
    void process();
}

// 2. Реальный объект с "тяжелой" инициализацией
class ExpensiveServiceImpl implements ExpensiveService {
    public ExpensiveServiceImpl() {
        // Долгая операция: загрузка из БД, чтение файла и т.д.
        System.out.println("Creating real ExpensiveService...");
    }
    @Override
    public void process() {
        System.out.println("Processing by real service.");
    }
}

// 3. Прокси-заместитель, откладывающий создание реального объекта
class ExpensiveServiceProxy implements ExpensiveService {
    private ExpensiveService realService; // Ссылка на реальный объект

    @Override
    public void process() {
        // Ленивая инициализация: создаем объект только при первом вызове
        if (realService == null) {
            realService = new ExpensiveServiceImpl();
        }
        // Делегируем вызов реальному объекту
        realService.process();
    }
}

// 4. Использование клиентом
public class Client {
    public static void main(String[] args) {
        // Реальный объект еще не создан
        ExpensiveService proxy = new ExpensiveServiceProxy();
        System.out.println("Proxy created.");
        // Реальный объект создается только здесь, при первом вызове
        proxy.process();
    }
}

Другие типы прокси и их применение:

  • Виртуальный прокси (как в примере): Для ленивой загрузки ресурсов.
  • Защищающий прокси (Protection Proxy): Для контроля прав доступа к объекту.
  • Удаленный прокси (Remote Proxy): Для представления объекта, находящегося в другом адресном пространстве (например, RPC, REST-клиент).
  • Прокси для логирования/кэширования: Добавляет сквозную функциональность.

Почему это полезно: Улучшает производительность и безопасность, разделяя ответственности.

Ответ 18+ 🔞

А, паттерн Прокси, ну это ж классика, блядь! Представь себе, что у тебя есть какой-нибудь тяжёлый, набуханный объект — ну там, который из базы данных полмиллиона записей грузит или в интернет лезет. Создавать его сразу — это ж, ёпта, как встать в пять утра на пробежку: вроде полезно, но нихуя не хочется.

И вот тут появляется этот самый прокси, такой хитрожопый заместитель. Он как тот твой друг, который говорит «да я договорюсь», а сам нихуя не делает, пока реально не припрет. Смотри, как это выглядит в коде, блядь.

Сначала они все, и реальная служба, и её заместитель-обманщик, договариваются говорить на одном языке — через интерфейс.

interface ExpensiveService {
    void process();
}

Дальше идёт сама служба, здоровенная, ленивая скотина. Её создание — это целая история, пиздец как долго.

class ExpensiveServiceImpl implements ExpensiveService {
    public ExpensiveServiceImpl() {
        // Долгая операция: загрузка из БД, чтение файла и т.д.
        System.out.println("Creating real ExpensiveService...");
    }
    @Override
    public void process() {
        System.out.println("Processing by real service.");
    }
}

А теперь — звезда вечера, наш прокси-обманщик. Он делает вид, что он и есть эта служба, но на самом деле он просто пустая болтовня, пока его не ткнут носом в работу.

class ExpensiveServiceProxy implements ExpensiveService {
    private ExpensiveService realService; // А реального-то объекта и нету ещё, блядь!

    @Override
    public void process() {
        // А вот тут начинается магия, ёпта! Ленивая инициализация, блядь.
        if (realService == null) {
            realService = new ExpensiveServiceImpl(); // Вот щас, сука, только щас мы его родим!
        }
        // А теперь делегируем вызов тому, кто реально должен пахать.
        realService.process();
    }
}

И как это всё работает в жизни? А вот так, в рот меня чих-пых!

public class Client {
    public static void main(String[] args) {
        // Создали прокси. Реальный объект? Не, не слышали. Он в отпуске.
        ExpensiveService proxy = new ExpensiveServiceProxy();
        System.out.println("Proxy created. Тишина, спокойствие, нихуя не происходит.");
        // А вот тут — БАЦ! — прокси понимает, что припёрло, и создаёт реальную тяжёлую хрень.
        proxy.process();
    }
}

И ведь это, блядь, только один вид, виртуальный прокси, для ленивой загрузки! А их, пидарасов, дохуя видов!

  • Защищающий прокси — стоит как вышибала в клубе и проверяет, есть ли у тебя права вызвать какой-нибудь метод. «Ты кто такой, блядь? А, админ? Проходи. А ты — читатель? Иди нахуй, только get() тебе доступен».
  • Удалённый прокси — это вообще анекдот. Он прикидывается локальным объектом, а сам, сука, шепчет по сети какому-нибудь удалённому сервису: «Э, братан, сделай там что надо и результат мне передай». Клиент думает, что всё рядом, а там RPC или REST, ебать его в сраку.
  • Прокси для логирования/кэширования — самый хитрый. Он как стукач: всё, что происходит, записывает. Или как жадная бабка: раз получил результат — спрятал в кэш, и следующий раз отдаёт из загашника, не беспокоя реальный объект.

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