Приведи пример реализации паттерна Фасад (Facade) в Swift.

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

Ответ

Фасад (Facade) — это структурный паттерн, который предоставляет простой, унифицированный интерфейс к сложной подсистеме, скрывая ее внутренние детали. Он упрощает использование системы для клиента.

Проблема: Клиентскому коду приходится взаимодействовать с множеством разнородных классов подсистемы, знать их API и порядок вызова.

Решение: Фасад инкапсулирует сложность, предоставляя один удобный метод.

Пример: Система домашнего кинотеатра

Сложная подсистема (классы, которые нужно скрыть):

class Projector {
    func on() { print("Projector: ON") }
    func off() { print("Projector: OFF") }
    func setInput(_ source: String) { print("Projector input set to: (source)") }
}

class AudioAmplifier {
    func on() { print("Amplifier: ON") }
    func off() { print("Amplifier: OFF") }
    func setVolume(_ level: Int) { print("Amplifier volume set to: (level)") }
    func setSurroundSound() { print("Amplifier: Surround sound ON") }
}

class BluRayPlayer {
    func on() { print("BluRay Player: ON") }
    func off() { print("BluRay Player: OFF") }
    func play(movie: String) { print("BluRay Player: Playing '(movie)'") }
}

class Lights {
    func dim(_ percentage: Int) { print("Lights dimmed to (percentage)%") }
}

Фасад, упрощающий взаимодействие:

class HomeTheaterFacade {
    private let projector: Projector
    private let amplifier: AudioAmplifier
    private let player: BluRayPlayer
    private let lights: Lights

    init(projector: Projector, amplifier: AudioAmplifier,
         player: BluRayPlayer, lights: Lights) {
        self.projector = projector
        self.amplifier = amplifier
        self.player = player
        self.lights = lights
    }

    // Простой метод, скрывающий сложность настройки системы
    func watchMovie(_ movieName: String) {
        print("n=== Getting ready to watch '(movieName)' ===")
        lights.dim(10)
        projector.on()
        projector.setInput("BluRay")
        amplifier.on()
        amplifier.setSurroundSound()
        amplifier.setVolume(8)
        player.on()
        player.play(movie: movieName)
        print("=== Enjoy the movie! ===n")
    }

    // Другой простой метод для выключения всего
    func endMovie() {
        print("n=== Shutting down the home theater ===")
        player.off()
        amplifier.off()
        projector.off()
        lights.dim(100)
    }
}

Использование клиентом:

// 1. Инициализация подсистемы (может быть сложной)
let projector = Projector()
let amplifier = AudioAmplifier()
let player = BluRayPlayer()
let lights = Lights()

// 2. Создание фасада
let homeTheater = HomeTheaterFacade(projector: projector,
                                    amplifier: amplifier,
                                    player: player,
                                    lights: lights)

// 3. Клиент использует простой интерфейс фасада
homeTheater.watchMovie("Inception")
// ... просмотр фильма ...
homeTheater.endMovie()

Вывод программы:

=== Getting ready to watch 'Inception' ===
Lights dimmed to 10%
Projector: ON
Projector input set to: BluRay
Amplifier: ON
Amplifier: Surround sound ON
Amplifier volume set to: 8
BluRay Player: ON
BluRay Player: Playing 'Inception'
=== Enjoy the movie! ===

=== Shutting down the home theater ===
BluRay Player: OFF
Amplifier: OFF
Projector: OFF
Lights dimmed to 100%

Преимущества паттерна Фасад:

  • Упрощает использование: Клиенту нужно знать только один класс (Фасад).
  • Снижает связанность: Клиент не зависит от множества классов подсистемы.
  • Не заставляет использовать: Клиент по-прежнему может обращаться к классам подсистемы напрямую, если это необходимо.