Objective-C 中的中介者模式原理与使用
中介者模式概述
中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介者对象来封装一系列对象之间的交互,使得这些对象之间不再直接相互引用,而是通过中介者进行通信。这样可以降低对象之间的耦合度,提高系统的可维护性和可扩展性。
在现实生活中,中介者模式有很多应用场景。例如,在机场的空中交通管制系统中,飞机(对象)之间并不直接通信决定如何起飞、降落或避让,而是通过空中交通管制塔台(中介者)来协调它们的行动。在电子商务平台中,买家、卖家和物流等各方之间的交互也是通过平台(中介者)来完成的。
Objective-C 中中介者模式的原理
模式结构
- 中介者(Mediator):定义了一个接口用于与各同事对象通信。在 Objective-C 中,通常是一个抽象类或者协议,具体的中介者类会实现这些接口方法。
- 具体中介者(ConcreteMediator):继承自中介者类或者实现中介者协议,实现与各同事对象通信的具体逻辑。它了解并维护所有同事对象的引用,并协调它们之间的交互。
- 同事(Colleague):定义了一个抽象类或者协议,包含了与中介者通信的方法。每个具体同事类都继承自这个抽象类或者实现该协议。
- 具体同事(ConcreteColleague):继承自同事抽象类或者实现同事协议,实现与中介者通信的具体逻辑。具体同事类持有中介者的引用,并通过中介者与其他同事对象进行交互。
降低耦合度的原理
在没有中介者模式的情况下,如果多个对象之间需要相互通信,每个对象都需要知道其他对象的存在,并直接调用其他对象的方法。这就导致对象之间的耦合度非常高,一旦某个对象的接口发生变化,可能会影响到所有与之直接通信的对象。
而中介者模式通过将对象之间的通信集中到中介者对象,每个对象只需要与中介者交互,而不需要了解其他对象的具体实现和接口。这样,当某个对象的接口发生变化时,只需要修改中介者中与之相关的逻辑,而不会影响到其他同事对象。
Objective-C 中中介者模式的使用场景
复杂交互系统
当系统中有多个对象之间存在复杂的交互关系,形成网状结构时,使用中介者模式可以将这些复杂的交互逻辑封装到中介者中,使得对象之间的关系变得清晰简单。例如,在一个多人在线游戏中,玩家之间的交互(如聊天、交易、组队等)可以通过一个游戏服务器(中介者)来协调,每个玩家(同事)只需要与游戏服务器交互,而不需要直接与其他玩家交互。
解耦对象之间的依赖
如果一些对象之间存在较强的依赖关系,为了降低它们之间的耦合度,可以引入中介者模式。比如,在一个音乐播放软件中,播放界面、歌曲列表、音量控制等模块之间存在交互。通过引入一个中介者对象,这些模块可以通过中介者进行通信,而不是直接相互引用,从而降低了模块之间的耦合度。
提高系统的可维护性和可扩展性
当系统需要添加新的对象或者修改现有对象的行为时,如果使用中介者模式,只需要在中介者中添加相应的逻辑,而不需要在各个对象之间进行大量的修改。这使得系统的维护和扩展变得更加容易。例如,在一个电商系统中,如果要添加新的促销活动模块,只需要在中介者中添加与促销活动模块交互的逻辑,而不会影响到其他已有的模块。
代码示例
定义中介者协议
首先,我们定义一个中介者协议 MediatorProtocol
,它声明了中介者需要实现的方法。
@protocol MediatorProtocol <NSObject>
- (void)colleagueChanged:(id)sender;
@end
定义同事抽象类
接下来,定义一个同事抽象类 Colleague
,它持有中介者的引用,并提供了一个与中介者通信的方法。
@interface Colleague : NSObject
@property (nonatomic, weak) id<MediatorProtocol> mediator;
- (instancetype)initWithMediator:(id<MediatorProtocol>)mediator;
- (void)sendMessage:(NSString *)message;
@end
@implementation Colleague
- (instancetype)initWithMediator:(id<MediatorProtocol>)mediator {
self = [super init];
if (self) {
_mediator = mediator;
}
return self;
}
- (void)sendMessage:(NSString *)message {
if ([self.mediator respondsToSelector:@selector(colleagueChanged:)]) {
[self.mediator colleagueChanged:self];
}
}
@end
定义具体同事类
我们定义两个具体同事类 ConcreteColleagueA
和 ConcreteColleagueB
,它们继承自 Colleague
类。
@interface ConcreteColleagueA : Colleague
@property (nonatomic, strong) NSString *message;
@end
@implementation ConcreteColleagueA
@end
@interface ConcreteColleagueB : Colleague
@property (nonatomic, strong) NSString *message;
@end
@implementation ConcreteColleagueB
@end
定义具体中介者类
然后,定义具体中介者类 ConcreteMediator
,它实现了 MediatorProtocol
协议,并且持有两个具体同事类的引用。
@interface ConcreteMediator : NSObject <MediatorProtocol>
@property (nonatomic, strong) ConcreteColleagueA *colleagueA;
@property (nonatomic, strong) ConcreteColleagueB *colleagueB;
@end
@implementation ConcreteMediator
- (void)colleagueChanged:(id)sender {
if ([sender isKindOfClass:[ConcreteColleagueA class]]) {
// 处理来自ConcreteColleagueA的消息
NSLog(@"收到ConcreteColleagueA的消息: %@", ((ConcreteColleagueA *)sender).message);
// 可以在这里转发消息给ConcreteColleagueB
if (self.colleagueB) {
self.colleagueB.message = ((ConcreteColleagueA *)sender).message;
[self.colleagueB sendMessage:self.colleagueB.message];
}
} else if ([sender isKindOfClass:[ConcreteColleagueB class]]) {
// 处理来自ConcreteColleagueB的消息
NSLog(@"收到ConcreteColleagueB的消息: %@", ((ConcreteColleagueB *)sender).message);
// 可以在这里转发消息给ConcreteColleagueA
if (self.colleagueA) {
self.colleagueA.message = ((ConcreteColleagueB *)sender).message;
[self.colleagueA sendMessage:self.colleagueA.message];
}
}
}
@end
使用中介者模式
在 main
函数中,我们创建中介者和具体同事对象,并演示它们之间的交互。
int main(int argc, const char * argv[]) {
@autoreleasepool {
ConcreteMediator *mediator = [[ConcreteMediator alloc] init];
ConcreteColleagueA *colleagueA = [[ConcreteColleagueA alloc] initWithMediator:mediator];
ConcreteColleagueB *colleagueB = [[ConcreteColleagueB alloc] initWithMediator:mediator];
mediator.colleagueA = colleagueA;
mediator.colleagueB = colleagueB;
colleagueA.message = @"Hello from Colleague A";
[colleagueA sendMessage:colleagueA.message];
colleagueB.message = @"Hello from Colleague B";
[colleagueB sendMessage:colleagueB.message];
}
return 0;
}
在上述代码中,ConcreteColleagueA
和 ConcreteColleagueB
通过 ConcreteMediator
进行通信。当 ConcreteColleagueA
发送消息时,ConcreteMediator
收到消息并可以选择将其转发给 ConcreteColleagueB
,反之亦然。这样,两个具体同事类之间不需要直接引用,降低了耦合度。
中介者模式与其他设计模式的关系
与观察者模式的对比
- 目的不同
- 观察者模式主要用于对象之间的一对多依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会收到通知并自动更新。例如,在一个新闻发布系统中,当有新的新闻发布时(主题对象状态改变),所有订阅该新闻类型的用户(观察者)都会收到通知。
- 中介者模式则着重于解耦多个对象之间复杂的网状交互关系,通过中介者来协调对象之间的通信,使得对象之间只与中介者交互,而不是相互直接交互。
- 交互方式不同
- 在观察者模式中,观察者和主题之间存在明确的依赖关系,主题知道观察者的存在,并主动通知观察者。
- 而在中介者模式中,同事对象之间并不知道彼此的存在,它们通过中介者间接通信,中介者负责管理和协调同事对象之间的交互。
与外观模式的对比
- 功能侧重不同
- 外观模式主要为子系统提供一个统一的接口,简化子系统与外部的交互。它将子系统的复杂性封装起来,使得外部调用者只需要与外观类交互,而不需要了解子系统内部的细节。例如,在一个多媒体播放系统中,外观类可以提供一个简单的
play
方法,内部封装了音频播放、视频解码等复杂的子系统操作。 - 中介者模式更关注于对象之间的交互,它通过中介者来处理对象之间复杂的通信和协作逻辑,降低对象之间的耦合度。
- 外观模式主要为子系统提供一个统一的接口,简化子系统与外部的交互。它将子系统的复杂性封装起来,使得外部调用者只需要与外观类交互,而不需要了解子系统内部的细节。例如,在一个多媒体播放系统中,外观类可以提供一个简单的
- 结构不同
- 外观模式通常只有一个外观类,它直接调用子系统的方法。
- 中介者模式中,中介者与多个同事对象交互,同事对象之间通过中介者间接通信,中介者维护着同事对象之间的关系并协调它们的交互。
中介者模式在 iOS 框架中的应用
UIKit 中的应用
在 iOS 的 UIKit 框架中,视图控制器(UIViewController
)可以看作是一种中介者。例如,在一个包含多个视图(UIView
)的界面中,这些视图之间可能需要进行交互,如一个按钮点击后改变另一个文本框的内容。视图控制器负责管理这些视图,并处理它们之间的交互逻辑。视图之间并不直接相互引用和通信,而是通过视图控制器这个“中介者”来协调。
NotificationCenter
NSNotificationCenter
也可以理解为一种中介者模式的应用。不同的对象(发布者和观察者)可以通过 NSNotificationCenter
进行间接通信。发布者发送通知,而观察者注册接收特定类型的通知。NSNotificationCenter
在这里充当了中介者的角色,它管理着通知的发布和接收,使得发布者和观察者之间不需要直接相互引用,降低了它们之间的耦合度。
实现中介者模式的注意事项
避免中介者对象过于复杂
如果中介者对象承担了过多的业务逻辑和交互协调工作,会导致中介者对象变得非常庞大和复杂,难以维护和扩展。在设计中介者时,应该尽量将逻辑进行合理拆分,避免中介者成为一个“超级对象”。可以根据业务功能将中介者的职责划分为多个较小的部分,或者引入多个中介者来分别处理不同类型的交互。
合理确定同事对象的职责
在设计同事对象时,要明确其职责范围,避免职责过重或过轻。同事对象应该专注于自身的业务功能,通过中介者与其他同事对象进行协作。如果同事对象的职责不清晰,可能会导致与中介者之间的交互逻辑混乱,影响系统的可维护性。
性能问题
在一些情况下,中介者模式可能会引入一定的性能开销,因为所有对象之间的通信都要经过中介者。特别是在对象数量较多且交互频繁的系统中,这种性能开销可能会比较明显。在这种情况下,可以考虑优化中介者的实现,例如使用更高效的数据结构来管理同事对象的引用,或者采用异步处理的方式来提高系统的响应性能。
通过以上对中介者模式在 Objective - C 中的原理、使用场景、代码示例以及与其他模式的关系等方面的介绍,相信你对中介者模式在 Objective - C 开发中的应用有了更深入的理解。在实际项目中,根据具体的业务需求合理地运用中介者模式,可以有效地提高代码的可维护性和可扩展性,降低对象之间的耦合度,从而构建出更加健壮和灵活的软件系统。