Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

Документы

Медиа

Назад
Вопрос про Java: design patterns, Proxy pattern, Adapter pattern, structural patterns, object-oriented design

В чем отличие Proxy от Adapter?

Вопрос проверяет понимание паттернов проектирования Proxy и Adapter, их целей и отличий, что важно для написания гибкого и поддерживаемого кода.

Короткий ответ

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

Длинный ответ

Паттерны Proxy и Adapter относятся к категории структурных паттернов проектирования, которые помогают организовать отношения между объектами. Хотя оба работают как обёртки (wrappers) вокруг других объектов, их цели и способы применения принципиально различны.

Цель паттерна Adapter

Adapter (Адаптер) используется, когда у вас есть класс (или объект) с нужной функциональностью, но его интерфейс не соответствует тому, который ожидает клиентский код. Адаптер преобразует интерфейс одного класса в интерфейс, понятный другому классу. Это позволяет работать вместе классам, которые изначально не были предназначены для этого.

Пример из жизни: переходник для розетки. У вас есть вилка от американского устройства (интерфейс A), но розетка европейская (интерфейс B). Адаптер (переходник) позволяет соединить их, не меняя ни устройство, ни розетку.

Цель паттерна Proxy

Proxy (Заместитель) предоставляет объект-заместитель, который контролирует доступ к другому объекту. Интерфейс Proxy идентичен интерфейсу оригинального объекта, поэтому клиент может работать с Proxy, не подозревая о подмене. Основные причины использования Proxy:

  • Ленивая инициализация (Virtual Proxy): отложить создание ресурсоёмкого объекта до момента реального использования.
  • Кэширование (Caching Proxy): сохранять результаты операций, чтобы избежать повторных вычислений.
  • Контроль доступа (Protection Proxy): проверять права клиента перед выполнением операции.
  • Логирование или мониторинг: добавлять дополнительную логику вокруг вызовов.

Пример кода: Adapter

Предположим, у нас есть старый класс OldPrinter с методом printDocument(), а новый клиентский код ожидает интерфейс NewPrinter с методом print(). Адаптер решит эту проблему.

// Старый класс, который нужно адаптировать
class OldPrinter {
    printDocument() {
        console.log('Printing document using old printer...');
    }
}

// Новый интерфейс, который ожидает клиент
class NewPrinter {
    print() {
        console.log('Printing...');
    }
}

// Адаптер наследует NewPrinter и использует OldPrinter внутри
class PrinterAdapter extends NewPrinter {
    constructor(oldPrinter) {
        super();
        this.oldPrinter = oldPrinter;
    }

    print() {
        // Преобразуем вызов нового интерфейса в старый
        this.oldPrinter.printDocument();
    }
}

// Использование
const oldPrinter = new OldPrinter();
const adapter = new PrinterAdapter(oldPrinter);
clientCode(adapter); // Клиент работает с NewPrinter, но вызывает старую функциональность

Пример кода: Proxy

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

// Интерфейс, который реализуют и реальный объект, и прокси
class Image {
    display() {}
}

// Реальный объект, создание которого может быть дорогим
class RealImage extends Image {
    constructor(filename) {
        super();
        this.filename = filename;
        this.loadFromDisk();
    }

    loadFromDisk() {
        console.log(`Loading image: ${this.filename}`);
    }

    display() {
        console.log(`Displaying image: ${this.filename}`);
    }
}

// Proxy контролирует доступ к RealImage
class ImageProxy extends Image {
    constructor(filename) {
        super();
        this.filename = filename;
        this.realImage = null; // Реальный объект создаётся лениво
    }

    display() {
        if (this.realImage === null) {
            this.realImage = new RealImage(this.filename);
        }
        this.realImage.display();
    }
}

// Использование
const image = new ImageProxy('photo.jpg');
// RealImage ещё не создан, загрузки с диска не происходит
image.display(); // Только здесь создаётся и загружается RealImage, затем отображается

Вывод: Используйте Adapter, когда вам нужно привести несовместимые интерфейсы к общему знаменателю, чтобы интегрировать старый код или сторонние библиотеки. Используйте Proxy, когда требуется добавить дополнительный уровень контроля над доступом к объекту (ленивая инициализация, кэширование, безопасность) без изменения его исходного кода или интерфейса, видимого клиенту.

Уровень

  • Рейтинг:

    3

  • Сложность:

    5

Навыки

  • Java

    Java

  • C#

    C#

Ключевые слова

#design patterns

#Proxy pattern

#Adapter pattern

#structural patterns

#object-oriented design

Подпишись на Java Developer в телеграм