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

«В чем разница между паттернами Proxy и Bridge?» — вопрос из категории Паттерны, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Оба паттерна относятся к структурным, но решают разные проблемы.

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

  • Цель: Контроль доступа к объекту, добавление логики (ленивая загрузка, кэширование, защита, логирование) без изменения его основного кода.
  • Структура: Прокси и реальный объект реализуют один и тот же интерфейс. Клиент работает с прокси, который делегирует вызовы реальному объекту при необходимости.
  • Пример (Ленивая загрузка изображения):
    
    protocol Image {
    func display()
    }

class RealImage: Image { init(filename: String) { / Дорогая загрузка с диска / } func display() { print("Отображение изображения") } }

class ProxyImage: Image { private let filename: String private lazy var realImage: RealImage = RealImage(filename: filename) // Ленивая инициализация

init(filename: String) { self.filename = filename }
func display() { realImage.display() } // Реальный объект создаётся только здесь

}

// Использование let image: Image = ProxyImage(filename: "photo.jpg") image.display() // RealImage загружается и отображается только в этот момент


### Bridge (Мост)
*   **Цель:** Разделить абстракцию (интерфейс) и её реализацию, чтобы они могли изменяться независимо. Позволяет избежать наследования в виде "кубика Lego".
*   **Структура:** Абстракция содержит ссылку на объект реализации (через общий протокол). Можно комбинировать разные абстракции с разными реализациями.
*   **Пример (Графические примитивы и рендереры):**
```swift
// Реализация
protocol Renderer {
    func renderCircle(radius: Float)
}

class VectorRenderer: Renderer {
    func renderCircle(radius: Float) { print("Рисуем круг линиями (радиус: (radius))") }
}

class RasterRenderer: Renderer {
    func renderCircle(radius: Float) { print("Рисуем круг пикселями (радиус: (radius))") }
}

// Абстракция
class Shape {
    let renderer: Renderer
    init(renderer: Renderer) { self.renderer = renderer }
    func draw() {}
}

class Circle: Shape {
    let radius: Float
    init(radius: Float, renderer: Renderer) {
        self.radius = radius
        super.init(renderer: renderer)
    }
    override func draw() {
        renderer.renderCircle(radius: radius) // Делегирование реализации
    }
}

// Использование
let vectorCircle = Circle(radius: 5, renderer: VectorRenderer())
let rasterCircle = Circle(radius: 10, renderer: RasterRenderer())
vectorCircle.draw() // Рисуем круг линиями (радиус: 5.0)
rasterCircle.draw() // Рисуем круг пикселями (радиус: 10.0)

Итог: Proxy управляет доступом к одному объекту, Bridge разделяет иерархии абстракции и реализации.