iOS 设计模式之十八(中介者模式)
一、概念
1、中介者模式的动机
现在QQ和微信基本是装机必备APP,就拿QQ来说,个人聊天可以一对一,假如多人聊天呢,那么就是多对多,用户之间的关系就是一个网状结构,这个时候可以创建一个QQ群,这样大家都可以进行交互。
在有些软件中,某些类/对象之间的相互调用关系错综复杂,类似QQ用户之间的关系,此时,我们特别需要一个类似“QQ群”一样的中间类来协调这些类/对象之间的复杂关系,以降低系统的耦合度。有一个设计模式正为此而诞生,它就是中介者模式。
2、中介者模式的定义
中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
通过引入中介者来简化对象之间的复杂交互,中介者模式是“迪米特法则”的一个典型应用。
3、中介者模式的4个角色
1)Mediator(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。
2)ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现协作行为,它维持了对各个同事对象的引用。
3)Colleague(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
4)ConcreteColleague(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。
4、中介者类承担了两方面的职责
1)中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,可通过中介者来实现间接调用。该中转作用属于中介者在结构上的支持。
2)协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致的和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。
5、结构图
中介者模式二、示例
中介者模式的核心在于中介者类的引入。
1)先创建一个Mediator类,表示抽象中介者;
2)然后创建ConcreteMediator类,继承自Mediator类,表示具体中介者;
3)然后创建Colleague类,表示抽象同事类;
4)最后创建三个类ZhangSan、LiSi和WangWu,继承自Colleague类,表示具体同事类;
具体代码如下:
Mediator类:
@interface Mediator : NSObject
- (void)add:(Colleague *)colleague;
- (void)sendMessage:(NSString *)message colleague:(Colleague *)colleague;
@end
@interface Mediator ()
@property(nonatomic, strong) NSMutableArray<Colleague *> *colleagues;
@end
@implementation Mediator
- (instancetype)init
{
self = [super init];
if (self) {
_colleagues = [NSMutableArray array];
}
return self;
}
- (void)add:(Colleague *)colleague {
[self.colleagues addObject:colleague];
}
- (void)sendMessage:(NSString *)message colleague:(Colleague *)colleague {}
@end
ConcreteMediator类:
@interface ConcreteMediator : Mediator
@end
@implementation ConcreteMediator
- (void)sendMessage:(NSString *)message colleague:(Colleague *)colleague {
Colleague *zhangSan = self.colleagues[0];
Colleague *liSi = self.colleagues[1];
Colleague *wangWu = self.colleagues[2];
if (colleague == zhangSan) {
[liSi getMessage:message]; // 通过中介者调用同事类的方法
[wangWu getMessage:message];
} else if (colleague == liSi) {
[zhangSan getMessage:message];
}
}
@end
Colleague类:
@interface Colleague : NSObject
@property(nonatomic, strong) Mediator *mediator; //维持一个抽象中介者的引用
- (instancetype)initWithMediator:(Mediator *)mediator;
- (void)sendMessage:(NSString *)message; //定义依赖方法,与中介者进行通信
- (void)getMessage:(NSString *)message; //声明自身方法,处理自己的行为
@end
@implementation Colleague
- (instancetype)initWithMediator:(Mediator *)mediator {
self = [super init];
if (self) {
_mediator = mediator;
}
return self;
}
- (void)sendMessage:(NSString *)message {}
- (void)getMessage:(NSString *)message {}
@end
ZhangSan、LiSi和WangWu类:
// ZhangSan
@interface ZhangSan : Colleague
@end
@implementation ZhangSan
- (void)sendMessage:(NSString *)message {
NSLog(@"张三发送消息:%@", message);
[self.mediator sendMessage:message colleague:self];
}
- (void)getMessage:(NSString *)message {
NSLog(@"张三接收消息:%@", message);
}
@end
// LiSi
@interface LiSi : Colleague
@end
@implementation LiSi
- (void)sendMessage:(NSString *)message {
NSLog(@"李四发送消息:%@", message);
[self.mediator sendMessage:message colleague:self];
}
- (void)getMessage:(NSString *)message {
NSLog(@"李四接收消息:%@", message);
}
@end
// WangWu
@interface WangWu : Colleague
@end
@implementation WangWu
- (void)sendMessage:(NSString *)message {
NSLog(@"王五发送消息:%@", message);
[self.mediator sendMessage:message colleague:self];
}
- (void)getMessage:(NSString *)message {
NSLog(@"王五接收消息:%@", message);
}
@end
运行代码:
- (void)viewDidLoad {
[super viewDidLoad];
// 创建中介者对象
ConcreteMediator *mediator = [ConcreteMediator new];
// 创建同事对象,传入同一个中介者
Colleague *zhangSan = [[ZhangSan alloc] initWithMediator:mediator];
Colleague *liSi = [[LiSi alloc] initWithMediator:mediator];
Colleague *wangWu = [[WangWu alloc] initWithMediator:mediator];
// 给中介者绑定三个对象
[mediator add:zhangSan];
[mediator add:liSi];
[mediator add:wangWu];
// 发送消息
[zhangSan sendMessage:@"我爱你们"];
NSLog(@"-----------------------");
[liSi sendMessage:@"我不喜欢张三"];
}
打印结果:
张三发送消息:我爱你们
李四接收消息:我爱你们
王五接收消息:我爱你们
-----------------------
李四发送消息:我不喜欢张三
张三接收消息:我不喜欢张三
三、总结
中介者模式将一个网状的系统结构变成一个以中介者对象为中心的星形结构,在这个星型结构中,使用中介者对象与其他对象的一对多关系来取代原有对象之间的多对多关系。
1、优点
1、简化了对象之间的交互:它用中介者和同事的一对多交互代替了原来同事之间的多对多交互,一对多关系更容易理解、维护和扩展,将原本难以理解的网状结构转换成相对简单的星型结构。
2、可将各同事对象解耦:中介者有利于各同事之间的松耦合,我们可以独立的改变和复用每一个同事和中介者,增加新的中介者和新的同事类都比较方便,更好地符合“开闭原则”。
3、减少子类生成:中介者将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成新的中介者子类即可,这使各个同事类可被重用,无须对同事类进行扩展。
2、缺点
在具体中介者类中包含了大量同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。
3、适用场景
1、系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解。
2、一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。
3、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的具体中介者类。
4、iOS应用举例
在进行iOS组件化的时候,就是利用中介者模式处理组件之间的交互。
Demo地址:iOS-Design-Patterns