何为中介者模式?
面向对象的设计鼓励把行为分散到不同对象中,这种分散可能导致对象之间的相互关联。在最糟糕的情况下,所有对象都彼此了解并相互操作。
虽然把行为分散到不同对象增强了可复用性,但是增加的相互关联又减少了获得的益处。增加的关联使得对象很难或不能在不依赖其他对象的情况下工作。应用程序的整体行为可能难以进行任何重大修改,因为行为分布于许多对象。于是结果可能是创建越来越多的子类,以支持应用程序中的任何新行为。
中介者模式:用一个对象来封装一系列对象的交互方式。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
何时使用中介者模式?
@:对象间的交互虽定义明确然而非常复杂,导致一组对象彼此依赖而且难以理解。
@:因为对象引用了许多其他对象并与其通讯,导致对象难以复用。
@:想要定制一个分布在多个类中的逻辑或行为,又不想生成太多的子类。
中介者模式的应用实例:
要是飞行员都争抢着起飞或降落机场而没有交通管制,会出现不可估量的危险。为了避免这种情况,飞行员就需要知道彼此的意图与位置。下面就如何知道彼此的位置来阐述中介者模式的应用。如下图所示,表示它们之间的关系。
抽象的AbstractRadarMediator定义了用于同Plane交互的一般行为。ConcreteRadarMediator为Plane定义了更加具体的行为,因此可以子类化AbstractRadarMediator,把各种Plane交互算法应用到相同或不同的Plane类型。如果应用程序只需要一个中介者,有时抽象的Mediator可以省略。
Plane的实例有一个Mediator实例的引用,同时AbstractRadarMediator的实例知道参与的每个对象。Plane的代码如下:
#import <Foundation/Foundation.h> @class AbstractRadarMediator; // import "AbstractRadarMediator.h",不能这样写,否则会出现相互导入,导致错误提示,头文件找不到 @interface Plane : NSObject @property (nonatomic, assign) float distance; //距离机场的距离 @property (nonatomic, assign) float otherPlaneDistance; //其他飞机的位置 @property (nonatomic, strong) AbstractRadarMediator *radarMediator; //保持雷达中介者的引用 - (void)noticeLocation; @end
#import "Plane.h" @implementation Plane - (void)noticeLocation { NSLog(@"通知其他飞机自己的位置"); } @end
Plane类中的noticeLocation方法的具体由其子类来进行扩充,通过这种方式可以定义多种行为。PlaneA与PlaneB的代码如下:
#import "Plane.h" @interface PlaneA : Plane - (void)noticeLocation; //重写该方法 @end
#import "PlaneA.h" #import "AbstractRadarMediator.h" @implementation PlaneA - (void)noticeLocation { [self.radarMediator noticeLocationToPlaneBWithDistance:self.distance]; } @end
#import "Plane.h" @interface PlaneB : Plane - (void)noticeLocation; // 重写该方法 @end
#import "PlaneB.h" #import "AbstractRadarMediator.h" @implementation PlaneB - (void)noticeLocation { [self.radarMediator noticeLocationToPlaneAWithDistance:self.distance]; } @end
在这里我们可以看到noticeLocation的实现,通过中介者的方式向另外一个对象传递消息,这样做的好处就是使各对象不需要显式地相互引用,从而使其松耦合,而且可以独立地改变它们之间的交互。在AbstractRadarMediator定义同Plane对象交互的一般行为,代码如下:
#import <Foundation/Foundation.h> #import "Plane.h" @interface AbstractRadarMediator : NSObject @property (nonatomic, strong) Plane *planeA; @property (nonatomic, strong) Plane *planeB; - (instancetype)initWithPlaneA:(Plane *)planeA planeB:(Plane *)planeB; - (void)noticeLocationToPlaneAWithDistance:(float)distance; - (void)noticeLocationToPlaneBWithDistance:(float)distance; @end
#import "AbstractRadarMediator.h" @implementation AbstractRadarMediator - (instancetype)initWithPlaneA:(Plane *)planeA planeB:(Plane *)planeB { self = [super init]; if (self) { _planeA = planeA; _planeB = planeB; } return self; } - (void)noticeLocationToPlaneAWithDistance:(float)distance { NSLog(@"由子类来实现"); } - (void)noticeLocationToPlaneBWithDistance:(float)distance { NSLog(@"由子类来实现"); } @end
在这里定义了noticeLocationToPlaneAWithDistance:(float)distance与noticeLocationToPlaneBWithDistance两种交互方式,但具体怎么交互,则由其相应的子类来完成,这样就更加灵活,方便为Plane对象提供各种交互算法。ConcreteRadarMediator类中的代码如下:
#import "AbstractRadarMediator.h" @interface ConcreteRadarMediator : AbstractRadarMediator // 重写这两个方法 - (void)noticeLocationToPlaneAWithDistance:(float)distance; - (void)noticeLocationToPlaneBWithDistance:(float)distance; @end
#import "ConcreteRadarMediator.h" @implementation ConcreteRadarMediator - (void)noticeLocationToPlaneAWithDistance:(float)distance { self.planeA.otherPlaneDistance = distance; } - (void)noticeLocationToPlaneBWithDistance:(float)distance { self.planeB.otherPlaneDistance = distance; } @end
到现在为止,上面已经介绍完中介者模式了,下面我们看下在客户端怎么使用中介者模式以及中介者模式带给我们的便利性,代码如下:
#import "ViewController.h" #import "Plane.h" #import "PlaneA.h" #import "PlaneB.h" #import "AbstractRadarMediator.h" #import "ConcreteRadarMediator.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; Plane *planeA = [[PlaneA alloc] init]; PlaneB *planeB = [[PlaneB alloc] init]; AbstractRadarMediator *radarMediator = [[ConcreteRadarMediator alloc] initWithPlaneA:planeA planeB:planeB]; planeA.radarMediator = radarMediator; //保持AbstractRadarMediator的引用 planeB.radarMediator = radarMediator; planeA.distance = 800.0f; planeB.distance = 1000.0f; [planeA noticeLocation]; NSLog(@"飞机B收到A的位置通知:%f", planeB.otherPlaneDistance); [planeB noticeLocation]; NSLog(@"飞机A收到B的位置通知:%f", planeA.otherPlaneDistance); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
输出端的内如如下:
2015-09-01 09:44:42.236 MediatorPatter[12407:407240] 飞机B收到A的位置通知:800.000000 2015-09-01 09:44:42.237 MediatorPatter[12407:407240] 飞机A收到B的位置通知:1000.000000
在这里我们就可以看到,planeA与planeB两个对象之间没有相互的引用,但却实现了两个对象之间的通信,这样就减少了两者之间的关联,从而使其耦合松散,这正是使用中介者模式的便利性。
Demo链接地址:https://github.com/guoshimeihua/MediatorPatter