MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C 中的中介者模式原理与使用

2023-08-125.6k 阅读

中介者模式概述

中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介者对象来封装一系列对象之间的交互,使得这些对象之间不再直接相互引用,而是通过中介者进行通信。这样可以降低对象之间的耦合度,提高系统的可维护性和可扩展性。

在现实生活中,中介者模式有很多应用场景。例如,在机场的空中交通管制系统中,飞机(对象)之间并不直接通信决定如何起飞、降落或避让,而是通过空中交通管制塔台(中介者)来协调它们的行动。在电子商务平台中,买家、卖家和物流等各方之间的交互也是通过平台(中介者)来完成的。

Objective-C 中中介者模式的原理

模式结构

  1. 中介者(Mediator):定义了一个接口用于与各同事对象通信。在 Objective-C 中,通常是一个抽象类或者协议,具体的中介者类会实现这些接口方法。
  2. 具体中介者(ConcreteMediator):继承自中介者类或者实现中介者协议,实现与各同事对象通信的具体逻辑。它了解并维护所有同事对象的引用,并协调它们之间的交互。
  3. 同事(Colleague):定义了一个抽象类或者协议,包含了与中介者通信的方法。每个具体同事类都继承自这个抽象类或者实现该协议。
  4. 具体同事(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

定义具体同事类

我们定义两个具体同事类 ConcreteColleagueAConcreteColleagueB,它们继承自 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;
}

在上述代码中,ConcreteColleagueAConcreteColleagueB 通过 ConcreteMediator 进行通信。当 ConcreteColleagueA 发送消息时,ConcreteMediator 收到消息并可以选择将其转发给 ConcreteColleagueB,反之亦然。这样,两个具体同事类之间不需要直接引用,降低了耦合度。

中介者模式与其他设计模式的关系

与观察者模式的对比

  1. 目的不同
    • 观察者模式主要用于对象之间的一对多依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会收到通知并自动更新。例如,在一个新闻发布系统中,当有新的新闻发布时(主题对象状态改变),所有订阅该新闻类型的用户(观察者)都会收到通知。
    • 中介者模式则着重于解耦多个对象之间复杂的网状交互关系,通过中介者来协调对象之间的通信,使得对象之间只与中介者交互,而不是相互直接交互。
  2. 交互方式不同
    • 在观察者模式中,观察者和主题之间存在明确的依赖关系,主题知道观察者的存在,并主动通知观察者。
    • 而在中介者模式中,同事对象之间并不知道彼此的存在,它们通过中介者间接通信,中介者负责管理和协调同事对象之间的交互。

与外观模式的对比

  1. 功能侧重不同
    • 外观模式主要为子系统提供一个统一的接口,简化子系统与外部的交互。它将子系统的复杂性封装起来,使得外部调用者只需要与外观类交互,而不需要了解子系统内部的细节。例如,在一个多媒体播放系统中,外观类可以提供一个简单的 play 方法,内部封装了音频播放、视频解码等复杂的子系统操作。
    • 中介者模式更关注于对象之间的交互,它通过中介者来处理对象之间复杂的通信和协作逻辑,降低对象之间的耦合度。
  2. 结构不同
    • 外观模式通常只有一个外观类,它直接调用子系统的方法。
    • 中介者模式中,中介者与多个同事对象交互,同事对象之间通过中介者间接通信,中介者维护着同事对象之间的关系并协调它们的交互。

中介者模式在 iOS 框架中的应用

UIKit 中的应用

在 iOS 的 UIKit 框架中,视图控制器(UIViewController)可以看作是一种中介者。例如,在一个包含多个视图(UIView)的界面中,这些视图之间可能需要进行交互,如一个按钮点击后改变另一个文本框的内容。视图控制器负责管理这些视图,并处理它们之间的交互逻辑。视图之间并不直接相互引用和通信,而是通过视图控制器这个“中介者”来协调。

NotificationCenter

NSNotificationCenter 也可以理解为一种中介者模式的应用。不同的对象(发布者和观察者)可以通过 NSNotificationCenter 进行间接通信。发布者发送通知,而观察者注册接收特定类型的通知。NSNotificationCenter 在这里充当了中介者的角色,它管理着通知的发布和接收,使得发布者和观察者之间不需要直接相互引用,降低了它们之间的耦合度。

实现中介者模式的注意事项

避免中介者对象过于复杂

如果中介者对象承担了过多的业务逻辑和交互协调工作,会导致中介者对象变得非常庞大和复杂,难以维护和扩展。在设计中介者时,应该尽量将逻辑进行合理拆分,避免中介者成为一个“超级对象”。可以根据业务功能将中介者的职责划分为多个较小的部分,或者引入多个中介者来分别处理不同类型的交互。

合理确定同事对象的职责

在设计同事对象时,要明确其职责范围,避免职责过重或过轻。同事对象应该专注于自身的业务功能,通过中介者与其他同事对象进行协作。如果同事对象的职责不清晰,可能会导致与中介者之间的交互逻辑混乱,影响系统的可维护性。

性能问题

在一些情况下,中介者模式可能会引入一定的性能开销,因为所有对象之间的通信都要经过中介者。特别是在对象数量较多且交互频繁的系统中,这种性能开销可能会比较明显。在这种情况下,可以考虑优化中介者的实现,例如使用更高效的数据结构来管理同事对象的引用,或者采用异步处理的方式来提高系统的响应性能。

通过以上对中介者模式在 Objective - C 中的原理、使用场景、代码示例以及与其他模式的关系等方面的介绍,相信你对中介者模式在 Objective - C 开发中的应用有了更深入的理解。在实际项目中,根据具体的业务需求合理地运用中介者模式,可以有效地提高代码的可维护性和可扩展性,降低对象之间的耦合度,从而构建出更加健壮和灵活的软件系统。