前言
在 App 中,我们常常遇到多个 UI 元素之间相互依赖,比如当列表框中的某一项被选中时,UILabel 会被更新为列表框中选定的值。又或者当用户在文本框输入了新的值时,需要将这个新的值加入到列表框的列表中。当更多的 UI 元素参与到这一错综复杂的关系之中时,情况可能变得难以控制,元素之间需要彼此了解并相互操作。又或者当从一个页面跳转到另一个页面时,需要了解目标页面所需参数等等。这个时候需要有一个集中化的角色组织各种 UI 元素在同一个语境下进行交互,称之为中介者(Mediator)。
什么是中介者模式
在面向对象的设计中鼓励把行为分散到不同对象中,这种分散可能导致对象之间的互相联系。在最糟糕的情况下,所有对象都彼此了解并相互操作。虽然把行为分散到不同对象增强了可复用性,但是增加的相互关联又减少了获得的益处。在这种情况下就需要中介者模式。中介者模式提供了一个中介类作为集中的场所,用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
什么时候使用中介者模式
- 对象之间的交互虽然定义明确但是非常复杂,导致一组对象彼此相互依赖,形成了网状结构。若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
- 对象引用了许多其它对象并与其通讯,导致对象难以复用
- 想要定制一个分布在多个类中的逻辑或行为,又不想生成太多子类。
中介者模式的优缺点
中介者模式的优点
- 降低了类的复杂度,将一对多转化成了一对一。
- 各个类之间的解耦。
- 符合迪米特原则。(一个类对于其他类知道的越少越好)
中介者模式的缺点
随着系统规模的增大,中介者会越来越庞大,变得复杂难以维护。
Cocoa 中的中介者模式
UIViewController
是一个抽象类,可以对其进行子类化以管理特定视图。UIKit 框架还提供了UIViewController
用于管理导航栏和工具栏对象的子类:UINavigationController
和UITabBarController
. 一个 UITabController
可以管理多个 UINavigationController
,而这些UINavigationController
又可以管理一个或多个 UIViewController
,每个控制器都有其关联的视图对象。除了管理视图(包括覆盖视图)之外,视图控制器还指定导航栏中显示的按钮和标题。
中介者模式的实现
-
定义中介者和对象遵守的协议
@protocol Mediator; @protocol Colleague <NSObject> @property (nonatomic, strong) id <Mediator> mediator; - (void)receive; - (void)send; @end @protocol Mediator <NSObject> - (void)register:(id<Colleague>)colleague; - (void)relay:(id<Colleague>)cl; @end
-
实现其方法
@interface ConcreteMediator : NSObject<Mediator> @end @interface ConcreteMediator () @property (nonatomic, strong) NSMutableArray <id<Colleague>> *colleagues; @end @implementation ConcreteMediator - (NSMutableArray<id<Colleague>> *)colleagues{ if (!_colleagues) { _colleagues = [NSMutableArray array]; } return _colleagues; } - (void)register:(id<Colleague>)colleague{ if ([colleague conformsToProtocol:@protocol(Colleague) ]){ if(![self.colleagues containsObject:colleague]){ [self.colleagues addObject:colleague]; [colleague setMediator:self]; } } } - (void)relay:(id<Colleague>)cl{ for (id <Colleague> colleague in self.colleagues) { if (![colleague isEqual:cl]) { [colleague receive]; } } } @end @interface ConcreteColleague1 : NSObject<Colleague> @end @implementation ConcreteColleague1 @synthesize mediator; - (void)receive { NSLog(@"对象1收到消息"); } - (void)send { NSLog(@"对象1发送消息"); if (self.mediator) { [self.mediator relay:self]; } } @end @interface ConcreteColleague2 : NSObject<Colleague> @end @implementation ConcreteColleague2 @synthesize mediator; - (void)receive { NSLog(@"对象2收到消息"); } - (void)send { NSLog(@"对象2发送消息"); if (self.mediator) { [self.mediator relay:self]; } } @end
-
最终调用对象方法时,会通过中介者进行管理、转发。
ConcreteMediator *mediator = [ConcreteMediator new]; ConcreteColleague1 *colleague1 = [[ConcreteColleague1 alloc] init]; ConcreteColleague2 *colleague2 = [[ConcreteColleague2 alloc] init]; [mediator register:colleague1]; [mediator register:colleague2]; [colleague1 send]; [colleague2 send];
总结
虽然对于处理应用程序行为分散到不同对象并且对象相互依存的情况,中介者模式非常有用,但是应当避免让中介者类过于庞大而难以维护。