Шаблоны программирования на Swift: Bridge

Bridge_example-2x

Тема сегодняшней статьи из цикла шаблоны программирования на Swift — шаблон Bridge.

Bridge

Книга вешает:

Представьте себе, что у нас есть что-то однотипное, к примеру у нас есть телефон и куча наушников. Если бы у каждого телефона был свой разъем, то мы могли бы пользоваться только одним типом наушников. Но Бог миловал! Собственно таже штука и с наушникам. Они могут выдавать различный звук, иметь различные дополнительные функции, но основная их цель – просто звучание:) И хорошо, что во многих случаях штекер у них одинаковый (я не говорю про различные студийные наушники:) ).

Собственно, Мост (Bridge) позволяет разделить абстракцию от реализации, так чтобы реализация в любой момент могла быть поменяна, не меняя при этом абстракции.

Когда использовать?

  1. Вам совершенно не нужна связь между абстракцией и реализацией.

  2. Собственно, как абстракцию так и имплементацию могут наследовать независимо.
  3. Вы не хотите чтобы изменения в реализации имело влияния на клиентский код.

Рассмотрим пример:

Создадим базовый класс для наушников со своим функционалом:

 

//
// proSwift.ru
//

class BaseHeadphones {
    func playSimpleSound(){
        print("Пш..")
    }
    func playBassSound() {
        print("Пш..")
    }
}

И его наследников — дорогие и дешевые наушники:

//
// proSwift.ru
//


class CheapHeadphones: BaseHeadphones {
    override func playSimpleSound() {
        print("Бип-бип пшшшшшшш")
    }
    
    override func playBassSound() {
        print("Бух-Бух  прррр")
    }
    
}



class ExpensiveHeadphones: BaseHeadphones {
    override func playSimpleSound() {
        print("Бип-Бип-Бип Тарам-пам-пам")
    }
    
    override func playBassSound() {
        print("Бам-бам-бам")
    }
    
}

Как видите, функционал у них свой, отличающийся от базовой абстракции.

И собственно плеер, через который мы будем слушать музыку:

//
// proSwift.ru
//

class MusicPlayer {
    var headPhones: BaseHeadphones?
    
    func playMusic() {
        headPhones?.playBassSound()
        headPhones?.playBassSound()
        headPhones?.playSimpleSound()
        headPhones?.playSimpleSound()
    }
}

Как видите, одно из свойств нашего плеера – наушники. Их можно подменять в любой момент, так как свойство того же типа, от которого наши дешевые и дорогие наушники наследуются.
Теперь тест!

//
// proSwift.ru
//


let player = MusicPlayer()
let ch = CheapHeadphones()
let ex = ExpensiveHeadphones()
player.headPhones = ch
player.playMusic()
print("- - - - - - - - - - -")
player.headPhones = ex
player.playMusic()

Вывод в консоль:

Бух-Бух  прррр
Бух-Бух  прррр
Бип-бип пшшшшшшш
Бип-бип пшшшшшшш
- - - - - - - - - - -
Бам-бам-бам
Бам-бам-бам
Бип-Бип-Бип Тарам-пам-пам
Бип-Бип-Бип Тарам-пам-пам

Как видно, все работает нормально. Наушники меняются и меняют функционал, при этом базовая абстракция у нас неизменна.

Пример с GitHub

Еще раз:

Шаблон Мост используется для разделения абстрактных элементов класса от деталей реализации, предоставляя средства для замены деталей реализации без изменения абстракции.

 

//
// proSwift.ru
//
// https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/source/structural/bridge.swift


protocol Switch {
    var appliance: Appliance {get set}
    func turnOn()
}

protocol Appliance {
    func start()
}

class RemoteControl: Switch {
    var appliance: Appliance
    
    func turnOn() {
        self.appliance.start()
    }
    
    init(appliance: Appliance) {
        self.appliance = appliance
    }
}

class TV: Appliance {
    func start() {
        print("tv turned on");
    }
}

class VacuumCleaner: Appliance {
    func start() {
        print("vacuum cleaner turned on")
    }
}



var tvRemoteControl = RemoteControl(appliance: TV())
tvRemoteControl.turnOn() // tv turned on

var fancyVacuumCleanerRemoteControl = RemoteControl(appliance: VacuumCleaner())
fancyVacuumCleanerRemoteControl.turnOn() // vacuum cleaner turned on

Итак, у нас есть протокол Прибор, который описывает функционал начала работы, протокол Выключатель, который описывает свойство типа Прибор и функцию включения прибора, которая вызывает функцию начала работы. Два различных прибора — телевизор и пылесос, несомненно, разные по сути приборы, но они оба могут начинать работать, и их можно использовать в одном классе дистанционного управления. Итог — после включения обоих приборов они начали работать.

Метки:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.