/ 设计模式 / 中介者模式 / Swift Swift 中介者模式讲解和代码示例 中介者是一种行为设计模式, 让程序组件通过特殊的中介者对象进行间接沟通, 达到减少组件之间依赖关系的目的。 中介者能使得程序更易于修改和扩展, 而且能更方便地对独立的组件进行复用, 因为它们不再依赖于很多其他的类。 进一步了解中介者模式 导航 简介 概念示例 Example Output 真实世界示例 Example Output 复杂度: 流行度: 使用示例: 中介者模式在 Swift 代码中最常用于帮助程序 GUI 组件之间的通信。 在 MVC 模式中, 控制器是中介者的同义词。 以下示例可在 Swift Playgrounds 上使用。 感谢 Alejandro Mohamad 创建了Playground版本。 概念示例 真实世界示例 概念示例 本例说明了中介者设计模式的结构并重点回答了下面的问题: 它由哪些类组成? 这些类扮演了哪些角色? 模式中的各个元素会以何种方式相互关联? 了解该模式的结构后, 你可以更容易地理解下面基于真实世界的 Swift 应用案例。 Example.swift: 概念示例 import XCTest /// The Mediator interface declares a method used by components to notify the /// mediator about various events. The Mediator may react to these events and /// pass the execution to other components. protocol Mediator: AnyObject { func notify(sender: BaseComponent, event: String) } /// Concrete Mediators implement cooperative behavior by coordinating several /// components. class ConcreteMediator: Mediator { private var component1: Component1 private var component2: Component2 init(_ component1: Component1, _ component2: Component2) { self.component1 = component1 self.component2 = component2 component1.update(mediator: self) component2.update(mediator: self) } func notify(sender: BaseComponent, event: String) { if event == "A" { print("Mediator reacts on A and triggers following operations:") self.component2.doC() } else if (event == "D") { print("Mediator reacts on D and triggers following operations:") self.component1.doB() self.component2.doC() } } } /// The Base Component provides the basic functionality of storing a mediator's /// instance inside component objects. class BaseComponent { fileprivate weak var mediator: Mediator? init(mediator: Mediator? = nil) { self.mediator = mediator } func update(mediator: Mediator) { self.mediator = mediator } } /// Concrete Components implement various functionality. They don't depend on /// other components. They also don't depend on any concrete mediator classes. class Component1: BaseComponent { func doA() { print("Component 1 does A.") mediator?.notify(sender: self, event: "A") } func doB() { print("Component 1 does B.\n") mediator?.notify(sender: self, event: "B") } } class Component2: BaseComponent { func doC() { print("Component 2 does C.") mediator?.notify(sender: self, event: "C") } func doD() { print("Component 2 does D.") mediator?.notify(sender: self, event: "D") } } /// Let's see how it all works together. class MediatorConceptual: XCTestCase { func testMediatorConceptual() { let component1 = Component1() let component2 = Component2() let mediator = ConcreteMediator(component1, component2) print("Client triggers operation A.") component1.doA() print("\nClient triggers operation D.") component2.doD() print(mediator) } } Output.txt: 执行结果 Client triggers operation A. Component 1 does A. Mediator reacts on A and triggers following operations: Component 2 does C. Client triggers operation D. Component 2 does D. Mediator reacts on D and triggers following operations: Component 1 does B. Component 2 does C. 真实世界示例 Example.swift: 真实世界示例 import XCTest class MediatorRealWorld: XCTestCase { func test() { let newsArray = [News(id: 1, title: "News1", likesCount: 1), News(id: 2, title: "News2", likesCount: 2)] let numberOfGivenLikes = newsArray.reduce(0, { $0 + $1.likesCount }) let mediator = ScreenMediator() let feedVC = NewsFeedViewController(mediator, newsArray) let newsDetailVC = NewsDetailViewController(mediator, newsArray.first!) let profileVC = ProfileViewController(mediator, numberOfGivenLikes) mediator.update([feedVC, newsDetailVC, profileVC]) feedVC.userLikedAllNews() feedVC.userDislikedAllNews() } } class NewsFeedViewController: ScreenUpdatable { private var newsArray: [News] private weak var mediator: ScreenUpdatable? init(_ mediator: ScreenUpdatable?, _ newsArray: [News]) { self.newsArray = newsArray self.mediator = mediator } func likeAdded(to news: News) { print("News Feed: Received a liked news model with id \(news.id)") for var item in newsArray { if item == news { item.likesCount += 1 } } } func likeRemoved(from news: News) { print("News Feed: Received a disliked news model with id \(news.id)") for var item in newsArray { if item == news { item.likesCount -= 1 } } } func userLikedAllNews() { print("\n\nNews Feed: User LIKED all news models") print("News Feed: I am telling to mediator about it...\n") newsArray.forEach({ mediator?.likeAdded(to: $0) }) } func userDislikedAllNews() { print("\n\nNews Feed: User DISLIKED all news models") print("News Feed: I am telling to mediator about it...\n") newsArray.forEach({ mediator?.likeRemoved(from: $0) }) } } class NewsDetailViewController: ScreenUpdatable { private var news: News private weak var mediator: ScreenUpdatable? init(_ mediator: ScreenUpdatable?, _ news: News) { self.news = news self.mediator = mediator } func likeAdded(to news: News) { print("News Detail: Received a liked news model with id \(news.id)") if self.news == news { self.news.likesCount += 1 } } func likeRemoved(from news: News) { print("News Detail: Received a disliked news model with id \(news.id)") if self.news == news { self.news.likesCount -= 1 } } } class ProfileViewController: ScreenUpdatable { private var numberOfGivenLikes: Int private weak var mediator: ScreenUpdatable? init(_ mediator: ScreenUpdatable?, _ numberOfGivenLikes: Int) { self.numberOfGivenLikes = numberOfGivenLikes self.mediator = mediator } func likeAdded(to news: News) { print("Profile: Received a liked news model with id \(news.id)") numberOfGivenLikes += 1 } func likeRemoved(from news: News) { print("Profile: Received a disliked news model with id \(news.id)") numberOfGivenLikes -= 1 } } protocol ScreenUpdatable: class { func likeAdded(to news: News) func likeRemoved(from news: News) } class ScreenMediator: ScreenUpdatable { private var screens: [ScreenUpdatable]? func update(_ screens: [ScreenUpdatable]) { self.screens = screens } func likeAdded(to news: News) { print("Screen Mediator: Received a liked news model with id \(news.id)") screens?.forEach({ $0.likeAdded(to: news) }) } func likeRemoved(from news: News) { print("ScreenMediator: Received a disliked news model with id \(news.id)") screens?.forEach({ $0.likeRemoved(from: news) }) } } struct News: Equatable { let id: Int let title: String var likesCount: Int /// Other properties static func == (left: News, right: News) -> Bool { return left.id == right.id } } Output.txt: 执行结果 News Feed: User LIKED all news models News Feed: I am telling to mediator about it... Screen Mediator: Received a liked news model with id 1 News Feed: Received a liked news model with id 1 News Detail: Received a liked news model with id 1 Profile: Received a liked news model with id 1 Screen Mediator: Received a liked news model with id 2 News Feed: Received a liked news model with id 2 News Detail: Received a liked news model with id 2 Profile: Received a liked news model with id 2 News Feed: User DISLIKED all news models News Feed: I am telling to mediator about it... ScreenMediator: Received a disliked news model with id 1 News Feed: Received a disliked news model with id 1 News Detail: Received a disliked news model with id 1 Profile: Received a disliked news model with id 1 ScreenMediator: Received a disliked news model with id 2 News Feed: Received a disliked news model with id 2 News Detail: Received a disliked news model with id 2 Profile: Received a disliked news model with id 2 概念示例 真实世界示例