В чем разница между паттернами Proxy и Bridge?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между паттернами 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
Сравнительная таблица
| Критерий | Proxy | Bridge |
|---|---|---|
| Цель | Контроль доступа к объекту | Разделение абстракции и реализации |
| Связь | Обёртка вокруг одного объекта | Мост между двумя иерархиями классов |
| Интерфейс | Совпадает с интерфейсом целевого объекта | Абстракция и реализация имеют разные интерфейсы |
| Гибкость | Добавляет поведение, но не меняет структуру | Позволяет независимо менять абстракции и реализации |
| Когда использовать | Когда нужен контроль, ленивая инициализация или кеширование | Когда нужно избежать постоянного связывания абстракции с реализацией |
Практические примеры в iOS
-
Proxy в iOS:
NSProxyдля создания прокси-объектов.- Ленивая загрузка больших изображений в
UIImageView. - Кеширование сетевых запросов через прокси-слой.
-
Bridge в iOS:
- Разделение
UIControl(абстракция) и конкретных реализаций (UIButton,UISwitch). - Адаптация различных API аналитики через общий интерфейс.
- Поддержка разных тем оформления в приложении.
- Разделение
Вывод
Proxy — это "страж" или "посредник", который добавляет дополнительный уровень косвенности для управления доступом к объекту. Bridge — это "архитектурный разделитель", который разрывает жёсткую связь между абстракцией и реализацией, позволяя им эволюционировать независимо. Если упростить: Proxy работает с одним объектом, добавляя поведение, а Bridge строит мост между двумя семействами объектов, обеспечивая гибкость архитектуры.