写在开头

之所以想聊聊中介者模式,是因为在之前关于iOS组件化方案的争论中拜读了bang大神的总结,他文中详细的介绍了如何利用中介者模式来解决模块之间的调用依赖。

聊聊中介者模式

中介者模式:用一个对象来封装一系列对象的交互方式。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。其类图如下:

图中描述的关系有,抽象Mediator会被ConcreteMediator实现,抽象Colleague会被ConcreteColleague1和ConcreteColleague2实现,抽象Colleague含有对抽象Mediator实例的引用,ConcreteMediator含有对ConcreteColleague1实例和ConcreteColleague2实例的引用。如果应用程序中只需要一个中介者,有时抽象的Mediator可以省略,一种可能的对象图如下:

在以下情形,自然会考虑使用这一模式:

  • 对象间的交互虽定义明确然而非常复杂,导致一组对象彼此相互依赖而且难以理解;
  • 因为对象引用了许多其他对象并与其通讯,导致对象难以复用;
  • 想要定制一个分布在多个类中的逻辑或行为,又不想生成太多子类。

中介者模式也可能带来弊端,便是中介者类过于庞大而难以维护。

实践中介者模式

Demo地址是https://github.com/monkiyang/MediatorPatternGo,关键代码摘录如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// MKMediator.m
...
+ (UIViewController *)viewControllerWithModuleClass:(NSString *)moduleClass selector:(NSString *)selector params:(NSDictionary *)params {
if (moduleClass.length == 0 || selector.length == 0 || !params) {
return nil;
}
//target-action解除MKMediator对MKModuleX的感官依赖,运行时仍存在依赖
Class cls = NSClassFromString(moduleClass);
SEL sel = NSSelectorFromString(selector);
if (!cls || !sel) {
return nil;
}
if ([cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
return [cls performSelector:sel withObject:params];
#pragma clang diagnostic pop
}
return nil;
}
...

参考资料

《Objective-C编程之道iOS设计模式解析》
iOS 组件化方案探索 by bang