Swift Design Patterns: Facade

Зачем нужен?

Паттерн Facade применяется, когда какой-то части клиента требуется упрощенный интерфейс, управляющий полной функциональностью сложной подсистемы.

Определение

  • предоставляет унифицированный интерфейс к группе интерфейсов подсистемы. Фасад определяет высокоуровневый интерфейс, упрощающий работу с подсистемой
  • обертывает(упаковывает) сложную подсистему в простой интерфейс

Реализация

Паттерн инкапсулирует сложную подсистему внутри одного простого интерфейса. Упрощает начальное использование подсистемы(при этом остается гибкость, если нужна сложная настройка), уменьшает связанность. К реализации нужно подходить осторожно - фасад легко превратить в god-объект, который управляет всем и вся.

Реализация похожа на паттерн адаптер, но задачи у них разные.

  1. Определите упрощенный интерфейс для подсистемы/компонента
  2. Спроектируйте класс-обертку(фасад), реализующий этот интерфейс
  3. Фасад управляет сложностью и взаимодействием компонентов с помощью делегации методов
  4. Клиент использует(связан) с фасадом

Пример

Допустим у нас сложная система домашнего кинотеатра: проектор, усилитель, cd-плеер, экран, освещение..

Чтобы все это включить надо потратить много времени. Вместо этого, определим упрощенный интерфейс: watchMovie() и endMovie.

Реализуем класс-обертку(фасад):

// фасад
class HomeTheaterFacade {
    // компоненты подсистемы, которые будет использовать фасад
    private let ampifier: Ampifier
    private let tuner: Tuner
    private let cdPlayer: CDPlayer
    private let projector: Projector
    private let theaterLights: TheaterLights
    private let screen: Screen
    private let popcornPopper: PopcornPopper
    
    init(ampifier: Ampifier, tuner: Tuner, cdPlayer: CDPlayer,
        projector: Projector, theaterLights: TheaterLights,
        screen: Screen, popper: PopcornPopper) {
        self.ampifier = ampifier
        self.tuner = tuner
        self.cdPlayer = cdPlayer
        self.projector = projector
        self.theaterLights = theaterLights
        self.screen = screen
        self.popcornPopper = popper
    }
    
    func watchMovie(movie: String) {
    }
    
    func endMovie() {
    }
}

С помощью делегации определим взаимодействие компонентов

    func watchMovie(movie: String) {
        print("Get ready to watch \(movie)")
        popcornPopper.on()
        popcornPopper.pop()
        theaterLights.dim()
        screen.down()
        projector.on()
        projector.wideScreenModeOn()
        ampifier.on()
        ampifier.setCD()
        ampifier.setVolume()
        cdPlayer.on()
        cdPlayer.play()
    }
    
    func endMovie() {
        print("Shutting down")
        popcornPopper.off()
        screen.up()
        projector.off()
        ampifier.off()
        cdPlayer.off()
    }

Дальше клиент использует класс-фасад HomeTheaterFacade и наслаждается просмотром фильмов.

В качестве другого примера - звонок в интернет магазин для заказа товара. Клиент взаимодействует с упрощенным интерфейсом(оператором), который заполняет заказ, форму оплаты, адрес доставки и тд.

Реализация паттерна Facade: