基本概念
在面向对象的设计中是鼓励把行为分散到不同的对象中的,虽然把行为分散到不同的对象之间能增加复用性,但是这样的话可能会导致对象与对象相互关联的越来越多,这样的话就会使对象很难在不依赖对象的情况下独立工作,而且由于行为分布于多个对象,如果我们要去修改某个行为的话可能就很难的去修改,这样的话我们去创建的类就会越来越多,通过这样的方式去支持应用程序的新行为。
中介者模式的话其实就是让对象的交互在一个中介者中进行处理,其他的对象不需要去进行彼此的交互,这样可以松散耦合,减少了它们之间的依赖的关系,其实也就是说我让这些对象的交互都通过一个中介者来做,这样的话,我那么类对象彼此的结构都可以进行一个很好的修改
在现实生活中其实中介者模式也是在很多方面都存在的,就比如说我们经常使用的电脑如果缺乏主板,那么CPU,显卡,声卡这些都无法与外界直接进行交互,其实这就是一个中介者。
在中介者模式中有几个概念我们是需要知道的,如下所示
- 1、抽象的中介者接口Mediator,这里面一般定义的是用于各个colleague交互的一般的行为
- 2、具体中介者实现对象ConcreteMeditor主要就是去维护各个同事对象,负责协调各个同事对象之间的交互关系,就好比电影中的一个导演,导演应该知道所有的参与影片的角色以及场景的变换,如果电影在这拍摄期间的需求有任何的改变,导演应该是第一个知道的,然后去进行资源和人力的调整。
- 3、抽象的同事类Colleague主要就是用于约束同事对象的类型,并且可以去实现一些同事类当中要进行交互的一些公共的功能。
- 4、具体的同事类ConcreteColleague 首先肯定要先实现自己的业务,如果要和其他的同事进行交互的话,就去通过引用的中介者来进行交互,一般来说每一个具体的同事类的对象都会去引用中介者对象
UML结构图
中介者模式的主要应用场景
- 1、对象之间的交互很复杂时,也就是说如果导致一组对象之间相互依赖这样耦合性会很强。
- 2、对象引用了很多其他的对象导致对象很难进行复用
- 3、想要做一个分布在多个类中的逻辑或者是行为,但是不想生成太多的类的。
其实MVP的架构用到的就是中介者模式的思想,我通过P层将view和viewController的业务逻辑都抽给P层,这样我在viewController当中只需要去调用P层提供的接口就好
下面就举一个CD设备设置去读取数据需要通过声卡和显卡去播放我的数据,这里我们不用让CD设备之间去引用声卡和显卡,这样形成紧耦合关系,而是我们去使用中介者模式,利用Computer作为一个中介,这里主要理解思想
抽象中介者
//抽象的中介者
//它会持有同事的引用
class ComputerMediator: NSObject {
func changed(colleague:ComputerColleague)
{
}
}
抽象同事
import UIKit
//抽象同事
class ComputerColleague: NSObject {
//持有中介者
var mediator:ComputerMediator
init(mediator:ComputerMediator) {
self.mediator = mediator
}
}
具体同事DisplayCard(显卡)
import UIKit
//显卡
class DisplayCard: ComputerColleague {
override init(mediator: ComputerMediator) {
super.init(mediator: mediator)
}
//播放视频数据
func videoPlay(data:String) {
print("播放视频...")
}
}
具体同事SoundCard(声卡)
import UIKit
//声卡
class SoundCard: ComputerColleague {
override init(mediator: ComputerMediator) {
super.init(mediator: mediator)
}
//播放视频数据
func soundPlay(data:String) {
print("播放音频...")
}
}
具体同事CD设备
import UIKit
//CD设备->负责读取光盘数据传递给电脑
class CDDevice: ComputerColleague {
private var data:String?
override init(mediator: ComputerMediator) {
super.init(mediator: mediator)
}
func read() -> String {
return self.data!
}
func load() {
//数据格式就是两个数据之间隔得是逗号,所以下面CPU也是这么解析数据的
self.data = "视频数据,音频数据"
mediator.changed(colleague: self)
}
}
具体同事CPU,里面定义了如何去解析数据就是通过decodeData方法,这个方法就是专门为了解析我CD里面固定格式的数据来生成的,这里decodeData之后,又去调用中介者的change方法就是把数据给传递给了声卡和显卡,下面在Computer中介者类当中会有介绍
import UIKit
//同事
class CPU: ComputerColleague {
//视频数据
private var videoData:String?
//音频数据
private var soundData:String?
override init(mediator: ComputerMediator) {
super.init(mediator: mediator)
}
func getVideoData() -> String {
return self.videoData!
}
func getSoundData() -> String {
return self.soundData!
}
func decodeData(data:String) {
let array = data.split(separator: ",").map(String.init)
self.videoData = array[0]
self.soundData = array[1]
mediator.changed(colleague: self)
}
}
然后就是具体的中介者SXComputerMediator
import UIKit
//具体的中介者
class SXComputerMediator: ComputerMediator {
private var cpu:CPU?
private var displayCard:DisplayCard?
private var soundCard:SoundCard?
private var cdDevice:CDDevice?
func setCPU(cpu:CPU) {
self.cpu = cpu
}
func setDisplayCard(displayCard:DisplayCard) {
self.displayCard = displayCard
}
func setSoundCard(soundCard:SoundCard) {
self.soundCard = soundCard
}
func setCDDevice(cdDevice:CDDevice) {
self.cdDevice = cdDevice
}
override func changed(colleague: ComputerColleague) {
if colleague == cpu {
self.handleCPU(cpu: colleague as! CPU)
} else if colleague == cdDevice {
self.handleCD(cd: colleague as! CDDevice)
}
}
//CPU读取数据
//解析数据
private func handleCD(cd:CDDevice) {
cpu?.decodeData(data: cd.read())
}
//设备交互
private func handleCPU(cpu:CPU) {
self.soundCard?.soundPlay(data: cpu.getSoundData())
self.displayCard?.videoPlay(data: cpu.getVideoData())
}
}
然后就是我们进行使用,去创建中介者对象,然后设置好其的同事之后,直接调用同事的方法
let mediator = SXComputerMediator()
//零件->同事
let cpu = CPU(mediator: mediator)
let displayCard = DisplayCard(mediator: mediator)
let soundCard = SoundCard(mediator: mediator)
let cdDevice = CDDevice(mediator: mediator)
mediator.setCPU(cpu: cpu)
mediator.setSoundCard(soundCard: soundCard)
mediator.setDisplayCard(displayCard: displayCard)
mediator.setCDDevice(cdDevice:cdDevice)
cdDevice.load()
下面就是显示的结果,解析数据成功
当然如果我们使用了中介者模式的话,是以中介者内部的复杂的业务逻辑的判断去取代了交互的复杂性,因为中介者去封装了和合并了colleague的各种的协作的逻辑,所以中介者可能会变得很复杂很难进行维护。这样的话其实我们可以去使用策略模式来进行分解。当然策略模式主要是对固定的算法进行应用的,所以我们使用的时候也要注意