← Назад к вопросам

В чем разница между паттернами Proxy и Bridge?

2.0 Middle🔥 111 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между паттернами Proxy и Bridge

Оба паттерна относятся к структурным паттернам проектирования и имеют дело с композицией объектов, но решают принципиально разные задачи. Их часто путают из-за схожести в использовании делегирования, однако ключевое отличие лежит в намерении (intent) и проблемной области.

Основное назначение

Паттерн Proxy (Заместитель)

Proxy контролирует доступ к оригинальному объекту, выступая его суррогатом или обёрткой. Он предоставляет тот же интерфейс, что и реальный объект, но добавляет дополнительную логику до, после или вместо вызова методов целевого объекта. Основные цели:

  • Ленивая инициализация (virtual proxy) — отложенное создание ресурсоёмкого объекта.
  • Защита доступа (protection proxy) — проверка прав доступа.
  • Кеширование (caching proxy) — сохранение результатов вычислений.
  • Логирование и мониторинг — учёт вызовов.
  • Удалённый доступ (remote proxy) — представление объекта в другом адресном пространстве.

Паттерн Bridge (Мост)

Bridge разделяет абстракцию (интерфейс) и её реализацию, позволяя им изменяться независимо. Он решает проблему "наследования от конкретных классов", заменяя его композицией. Основные цели:

  • Избежать постоянного роста иерархии классов из-за комбинации абстракций и реализаций.
  • Позволить изменять реализацию во время выполнения.
  • Отделить бизнес-логику (абстракцию) от платформо-зависимого кода (реализацию).

Ключевые различия в структуре

Proxy

  • Связь 1 к 1: Proxy знает конкретный класс или интерфейс целевого объекта.
  • Одинаковый интерфейс: Proxy реализует тот же интерфейс, что и реальный объект.
  • Делегирование: Все вызовы перенаправляются целевому объекту, возможно, с доп. логикой.

Пример на Swift (Virtual Proxy):

protocol Image {
    func display()
}

class RealImage: Image {
    let filename: String
    
    init(filename: String) {
        self.filename = filename
        loadFromDisk()
    }
    
    private func loadFromDisk() {
        print("Загрузка изображения \(filename) с диска")
    }
    
    func display() {
        print("Отображение изображения \(filename)")
    }
}

class ProxyImage: Image {
    private var realImage: RealImage?
    private let filename: String
    
    init(filename: String) {
        self.filename = filename
    }
    
    func display() {
        if realImage == nil {
            realImage = RealImage(filename: filename) // Ленивая инициализация
        }
        realImage?.display()
    }
}

// Использование
let image: Image = ProxyImage(filename: "photo.jpg")
image.display() // RealImage создаётся только здесь

Bridge

  • Разделение на две иерархии: Абстракция (Abstraction) и Реализация (Implementor).
  • Композиция: Абстракция содержит ссылку на Implementor.
  • Независимое развитие: Можно добавлять новые абстракции и реализации без влияния друг на друга.

Пример на Swift (UI-компоненты и темы):

// Реализация (Implementor)
protocol Theme {
    var backgroundColor: String { get }
    var textColor: String { get }
}

class DarkTheme: Theme {
    var backgroundColor: String { return "#000000" }
    var textColor: String { return "#FFFFFF" }
}

class LightTheme: Theme {
    var backgroundColor: String { return "#FFFFFF" }
    var textColor: String { return "#000000" }
}

// Абстракция (Abstraction)
protocol UIComponent {
    var theme: Theme { get set }
    func render()
}

class Button: UIComponent {
    var theme: Theme
    
    init(theme: Theme) {
        self.theme = theme
    }
    
    func render() {
        print("Отрисовка кнопки с фоном \(theme.backgroundColor) и текстом \(theme.textColor)")
    }
}

class Alert: UIComponent {
    var theme: Theme
    
    init(theme: Theme) {
        self.theme = theme
    }
    
    func render() {
        print("Отрисовка алерта с фоном \(theme.backgroundColor) и текстом \(theme.textColor)")
    }
}

// Использование
let darkTheme = DarkTheme()
let button = Button(theme: darkTheme)
button.render() // Можно легко сменить тему на LightTheme

Сравнительная таблица

КритерийProxyBridge
ЦельКонтроль доступа к объектуРазделение абстракции и реализации
СвязьОбёртка вокруг одного объектаМост между двумя иерархиями классов
ИнтерфейсСовпадает с интерфейсом целевого объектаАбстракция и реализация имеют разные интерфейсы
ГибкостьДобавляет поведение, но не меняет структуруПозволяет независимо менять абстракции и реализации
Когда использоватьКогда нужен контроль, ленивая инициализация или кешированиеКогда нужно избежать постоянного связывания абстракции с реализацией

Практические примеры в iOS

  • Proxy в iOS:

    • NSProxy для создания прокси-объектов.
    • Ленивая загрузка больших изображений в UIImageView.
    • Кеширование сетевых запросов через прокси-слой.
  • Bridge в iOS:

    • Разделение UIControl (абстракция) и конкретных реализаций (UIButton, UISwitch).
    • Адаптация различных API аналитики через общий интерфейс.
    • Поддержка разных тем оформления в приложении.

Вывод

Proxy — это "страж" или "посредник", который добавляет дополнительный уровень косвенности для управления доступом к объекту. Bridge — это "архитектурный разделитель", который разрывает жёсткую связь между абстракцией и реализацией, позволяя им эволюционировать независимо. Если упростить: Proxy работает с одним объектом, добавляя поведение, а Bridge строит мост между двумя семействами объектов, обеспечивая гибкость архитектуры.

В чем разница между паттернами Proxy и Bridge? | PrepBro