Шаблоны программирования на Swift: Mediator
Давайте разберем шаблон программирования Mediator на Swift
Mediator
Медиатор – паттерн который определяет внутри себя объект, в котором реализуется взаимодействие между некоторым количеством объектов. При этом эти объекты, могут даже не знать про существования друг друга, потому взаимодействий реализованых в медиаторе может быть огромное количество.
Когда стоит использовать:
- Когда у вас есть некоторое количество объектов, и очень тяжело реализовать взаимодействие между ними. Яркий пример – умный дом. Онозначно есть несколько датчиков, и несколько устройств. К примеру, датчик температуры следит за тем какая на даный момент температура, а кондционер умеет охлаждать воздух. При чем кондиционер, не обязательно знает про существование датчика температуры. Есть центральный компьютер, который получает сигналы от каждого из устройств и понимает, что делать в том или ином случает.
- Тяжело переиспользовать объект, так как он взаимодействует и коммуницирует с огромным количеством других объектов.
- Логика взаимодействия должна легко настраиваться и расширяться.
Собственно, пример медиатора даже писать безсмысленно, потому как это любой контроллер который мы используем во время нашей разработки. Посудите сами – на view есть очень много контролов, и все правила взаимодействия мы прописываем в контроллере. Элементарно.
И все же пример не будет лишним Давайте все же создадим пример который показывает создание аля умного дома.
Пускай у нас есть оборудование которое может взаимодействоать с нашим умным домом:
// // proSwift.ru // class SmartHousePart { private weak var processor: CentralProcessor init(withCore processor: CentralProcessor) { self .processor = processor } func numberChanged() { processor.valueChanged(self) } }
Теперь, создадим сердце нашего умного дома:
// // proSwift.ru // class CentralProcessor { var thermometer: Thermometer? var condSystem: ConditioningSystem? func valueChanged(aPart: SmartHousePart) { print("значение изменилось! нужно что-то сделать") // Определяем, что изменилась именно темперетура if aPart is Thermometer { print("Да - изменилась именно температура, включим кондер...") condSystem?.startCondition() } } }
В классе CentrallProcessor в методе valueChanged мы определяем с какой деталью и что произошло, чтобы адекватно среагировать. В нашем примере – изменение температуры приводт к тому что мы включаем кондиционер.
А вот, и код термометра и кондиционера:
// // proSwift.ru // class Thermometer: SmartHousePart { var temperature: Int? func temperatureChanged(temperature: Int) { self.temperature = temperature self.numberChanged() } } class ConditioningSystem: SmartHousePart { func startCondition() { print("Охлаждаю") } }
Как видим в результате у нас есть два объекта, которые друг про друга не в курсе, и все таки они взаимодействуют друг с другом посредством нашего медиатора CentrallProcessor. Запустим тестирование.
// // proSwift.ru // let processor = CentralProcessor() let therm = Thermometer(withCore: processor) let cond = ConditioningSystem(withCore: processor) processor.condSystem = cond processor.thermometer = therm therm.temperatureChanged(45)
Вывод лога в консоль:
значение изменилось! нужно что-то сделать Да - изменилась именно температура, включим кондер... Охлаждаю
Пример с GitHub
Шаблон Mediator используется для уменьшения связи между классами, которые взаимодействуют друг с другом. Вместо того, чтобы классы общались непосредственно друг с другом, и, таким образом, требуя знания о реализации друг-друга, классы отправляют сообщения объекту — посреднику и взаимодействуют с помощью этого посредника.
// // proSwift.ru // // https://github.com/ochococo/Design-Patterns-In-Swift/blob/master/source/structural/facade.swift class Colleague { let name: String let mediator: Mediator init(name: String, mediator: Mediator) { self.name = name self.mediator = mediator } func send(message: String) { mediator.send(message, colleague: self) } func receive(message: String) { assert(false, "Method should be overriden") } } protocol Mediator { func send(message: String, colleague: Colleague) } class MessageMediator: Mediator { private var colleagues: [Colleague] = [] func addColleague(colleague: Colleague) { colleagues.append(colleague) } func send(message: String, colleague: Colleague) { for c in colleagues { if c !== colleague { //for simplicity we compare object references c.receive(message) } } } } class ConcreteColleague: Colleague { override func receive(message: String) { print("Colleague \(name) received: \(message)") } } // ### Usage: let messagesMediator = MessageMediator() let user0 = ConcreteColleague(name: "0", mediator: messagesMediator) let user1 = ConcreteColleague(name: "1", mediator: messagesMediator) messagesMediator.addColleague(user0) messagesMediator.addColleague(user1) user0.send("Hello") // user1 receives message
Медиатор сообщений в данном примере собирает в массив всех коллег, и пытается отправить сообщение всем, кроме коллеги, который послал это сообщение. Это хороший пример того, что объектов, которыми управляет медиатор может быть множество. В данном примере коллег всего двое, но это не мешает создать их 1000, они друг о друге знать не будут, но смогут обмениваться сообщениями.
не нужно ли сделать слабую ссылку на процессор? будет утечка памяти
class SmartHousePart {
private weak var processor: CentralProcessor
Нужно! Вы правы