当涉及到模块化和组件化开发时,中介者模式(Mediator Pattern)可以帮助解耦不同模块之间的依赖关系。它通过提供一个统一的接口,将模块之间的通信和交互逻辑集中在一个中间件类中,而不是直接依赖于具体的模块。
中介者模式OC实现类
objectivec
// YJHMediator.h
#import <Foundation/Foundation.h>
@interface YJHMediator : NSObject
+ (instancetype)sharedInstance;
// 远程App调用入口
- (id)performActionWithUrl:(NSURL *)url completion:(void(^)(NSDictionary *info))completion;
// 本地组件调用入口
- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget;
- (void)releaseCachedTargetWithTargetName:(NSString *)targetName;
@end
//
#import "YJHMediator.h"
// 定义 YJHMediator 的私有接口
@interface YJHMediator ()
// 存储缓存的目标对象的字典
@property (nonatomic, strong) NSMutableDictionary *cachedTarget;
@end
// 实现 YJHMediator 类
@implementation YJHMediator
#pragma mark - public methods
// 单例方法,返回共享的 YJHMediator 实例
+ (instancetype)sharedInstance
{
static YJHMediator *mediator;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mediator = [[YJHMediator alloc] init];
});
return mediator;
}
/*
scheme://[target]/[action]?[params]
url sample:
aaa://targetA/actionB?id=1234
*/
// 根据 URL 执行对应的操作,并在完成时调用 completion 回调
- (id)performActionWithUrl:(NSURL *)url completion:(void (^)(NSDictionary *))completion
{
// 创建参数字典
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
// 获取 URL 的查询部分
NSString *urlString = [url query];
// 遍历查询部分,将参数解析为键值对并保存到 params 字典中
for (NSString *param in [urlString componentsSeparatedByString:@"&"]) {
NSArray *elts = [param componentsSeparatedByString:@"="];
if([elts count] < 2) continue;
[params setObject:[elts lastObject] forKey:[elts firstObject]];
}
// 根据 URL 的路径获取 actionName
NSString *actionName = [url.path stringByReplacingOccurrencesOfString:@"/" withString:@""];
// 检查 actionName 是否以 "native" 开头,如果是则返回 NO
if ([actionName hasPrefix:@"native"]) {
return @(NO);
}
// 调用 performTarget:action:params:shouldCacheTarget: 方法执行目标操作,并返回结果
id result = [self performTarget:url.host action:actionName params:params shouldCacheTarget:NO];
// 执行 completion 回调,并传递结果字典
if (completion) {
if (result) {
completion(@{@"result":result});
} else {
completion(nil);
}
}
// 返回结果
return result;
}
// 执行目标操作的方法
- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget
{
// 检查 targetName 和 actionName 是否为空
if (!targetName || !actionName) {
return nil;
}
// 构造目标类名
NSString *targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
// 构造方法名
NSString *actionString = [NSString stringWithFormat:@"IMP_%@", actionName];
// 如果 params 不为空,将冒号添加到 actionString 后面
if (params != nil) {
actionString = [actionString stringByAppendingString:@":"];
}
id target = nil;
// 使用同步锁保证多线程安全
@synchronized (self) {
target = self.cachedTarget[targetClassString];
}
// 如果缓存中没有目标对象,则根据 targetClassString 创建目标对象
if (target == nil) {
Class targetClass = NSClassFromString(targetClassString);
target = [[targetClass alloc] init];
}
SEL action = NSSelectorFromString(actionString);
// 如果目标对象为空,直接返回空
if (target == nil) {
return nil;
}
// 如果 shouldCacheTarget 为 YES,则将目标对象缓存起来
if (shouldCacheTarget) {
@synchronized (self) {
self.cachedTarget[targetClassString] = target;
}
}
// 检查目标对象是否响应 action 方法,如果是,则执行安全的方法调用
if ([target respondsToSelector:action]) {
return [self safePerformAction:action target:target params:params];
} else {
// 如果目标对象不响应 action 方法,则尝试调用目标对象的 notFound: 方法进行统一处理
SEL action = NSSelectorFromString(@"notFound:");
if ([target respondsToSelector:action]) {
return [self safePerformAction:action target:target params:params];
} else {
// 如果目标对象也没有 notFound: 方法,则直接返回空
return nil;
}
}
}
// 安全的方法调用,避免因为方法签名不匹配导致的崩溃
- (id)safePerformAction:(SEL)action target:(NSObject *)target params:(NSDictionary *)params
{
NSMethodSignature *methodSignature = [target methodSignatureForSelector:action];
if (methodSignature == nil) {
return nil;
}
const char *retType = [methodSignature methodReturnType];
if (strcmp(retType, @encode(void)) == 0) {
// 返回值为 void 的方法调用
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setSelector:action];
[invocation setTarget:target];
if (params) {
[invocation setArgument:¶ms atIndex:2];
}
[invocation invoke];
return nil;
} else if (strcmp(retType, @encode(NSInteger)) == 0) {
// 返回值为 NSInteger 的方法调用
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setSelector:action];
[invocation setTarget:target];
if (params) {
[invocation setArgument:¶ms atIndex:2];
}
[invocation invoke];
NSInteger result = 0;
[invocation getReturnValue:&result];
return @(result);
} else {
// 其他类型的返回值
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setSelector:action];
[invocation setTarget:target];
if (params) {
[invocation setArgument:¶ms atIndex:2];
}
[invocation invoke];
id result = nil;
[invocation getReturnValue:&result];
return result;
}
}
#pragma mark - getters and setters
- (NSMutableDictionary *)cachedTarget
{
if (!_cachedTarget) {
_cachedTarget = [[NSMutableDictionary alloc] init];
}
return _cachedTarget;
}
@end
如何使用
使用 YJHMediator
类可以实现对象之间的解耦和相互调用。下面是使用 YJHMediator
的一般步骤:
-
创建目标对象:首先,需要创建一个或多个目标对象,这些对象包含想要调用的方法。每个目标对象都应该是一个独立的类,并遵循特定的命名规则。
-
实现目标对象的方法:在每个目标对象类中,实现想要调用的方法。确保方法的命名以 "IMP_" 开头,例如
IMP_doSomething:
。方法的参数应该是一个NSDictionary
类型的参数。 -
调用目标对象方法:在需要调用目标对象方法的地方,使用
YJHMediator
的performTarget:action:params:shouldCacheTarget:
方法来调用指定目标对象的指定方法。传入目标对象名称、方法名称和参数。根据需要,可以选择是否缓存目标对象。 -
完成调用并处理结果:根据你的需求,可以在调用方法后处理返回的结果。
下面是一个简单的示例,演示如何使用 YJHMediator
:
objective-c
// 创建目标对象类
@interface Target_A : NSObject
- (void)IMP_doSomething:(NSDictionary *)params;
@end
@implementation Target_A
- (void)IMP_doSomething:(NSDictionary *)params {
NSString *message = params[@"message"];
NSLog(@"Target A is doing something with message: %@", message);
}
@end
// 在适当的地方调用目标对象的方法
NSDictionary *params = @{@"message": @"Hello, XCMediator!"};
[[YJHMediator sharedInstance] performTarget:@"A" action:@"doSomething" params:params shouldCacheTarget:NO];
// 输出结果:Target A is doing something with message: Hello, XCMediator!
在上面的示例中,我们创建了一个名为 Target_A
的目标对象类,并实现了 IMP_doSomething:
方法。然后,我们通过 YJHMediator
的 performTarget:action:params:shouldCacheTarget:
方法调用了 Target_A
类的 doSomething
方法,并传入了一个包含消息的参数字典。最后,Target_A
的 doSomething
方法被调用,并输出相应的日志信息。
请注意,这只是一个简单的示例,实际使用中可能涉及更复杂的业务逻辑和多个目标对象。确保根据你的需求适当地组织和管理目标对象和方法,并遵循命名规则以使 YJHMediator
能够正确识别和调用它们。
示例
- 创建目标对象:首先,需要创建一个或多个目标对象,这些对象包含想要调用的方法。每个目标对象都应该是一个独立的类,并遵循特定的命名规则。
- 实现目标对象的方法:在每个目标对象类中,实现想要调用的方法。确保方法的命名以 "IMP_" 开头,例如
IMP_doSomething:
。方法的参数应该是一个NSDictionary
类型的参数。
objectivec
// Target_TTHomeMoudle.h
#import <UIKit/UIKit.h>
typedef void(^TTSearchPresentDidClickBlock)(long long, NSString *);
@interface Target_TTHomeMoudle : NSObject
- (UIViewController *)IMP_TTSearchRoomViewController:(NSDictionary *)dict;
@end
ini
// Target_TTHomeMoudle.m
#import "Target_TTHomeMoudle.h"
#import "TTSearchRoomViewController.h"
@implementation Target_TTHomeMoudle
- (UIViewController *)IMP_TTSearchRoomViewController:(NSDictionary *)dict {
TTSearchRoomViewController *searchVC = [[TTSearchRoomViewController alloc] init];
if ([dict.allKeys containsObject:@"isPresent"]) {
searchVC.isPresent = dict[@"isPresent"];
}
if ([dict.allKeys containsObject:@"isInvite"]) {
searchVC.isInvite = dict[@"isInvite"];
}
if ([dict.allKeys containsObject:@"isHallSearch"]) {
searchVC.isHallSearch = dict[@"isHallSearch"];
}
//允许显示历史记录
if ([dict.allKeys containsObject:@"showHistoryRecord"]) {
searchVC.showHistoryRecord = [dict[@"showHistoryRecord"] boolValue];
}
if ([dict.allKeys containsObject:@"block"]) {
searchVC.searchPresentDidClickBlock = dict[@"block"];
}
if ([dict.allKeys containsObject:@"dismissBlock"]) {
searchVC.dismissAndDidClickPersonBlcok = dict[@"dismissBlock"];
}
if ([dict.allKeys containsObject:@"enterRoomBlock"]) {
searchVC.enterRoomHandler = dict[@"enterRoomBlock"];
}
return searchVC;
}
@end
- 调用目标对象方法:在需要调用目标对象方法的地方,使用
YJHMediator
的performTarget:action:params:shouldCacheTarget:
方法来调用指定目标对象的指定方法。传入目标对象名称、方法名称和参数。根据需要,可以选择是否缓存目标对象。 - 完成调用并处理结果:根据你的需求,可以在调用方法后处理返回的结果。
例如创建一个YJHMediator的分类定义一个方法使用 YJHMediator
的 performTarget:action:params:shouldCacheTarget:
方法来调用指定目标对象的指定方法
objectivec
// YJHMediator+TTHomeMoudle.h
#import "YJHMediator.h"
#import <UIKit/UIKit.h>
@interface YJHMediator (TTHomeMoudle)
/**
搜索控制器
*/
- (UIViewController *)homeMethod_CallName_searchRoomController:(BOOL)isPresent block:(id)block;
@end
objectivec
// YJHMediator+TTHomeMoudle.m
#import "YJHMediator+TTHomeMoudle.h"
@implementation YJHMediator (TTHomeMoudle)
/**
搜索控制器
*/
- (UIViewController *)homeMethod_CallName_searchRoomController:(BOOL)isPresent block:(id)block {
NSDictionary *params = @{@"isPresent" : @(isPresent), @"block" : block};
return [self performTarget:@"TTHomeMoudle" action:@"TTSearchRoomViewController" params:params shouldCacheTarget:YES];
}
@end