当涉及到模块化和组件化开发时,中介者形式(Mediator Pattern)能够帮助解耦不同模块之间的依靠关系。它通过供给一个统一的接口,将模块之间的通讯和交互逻辑会集在一个中间件类中,而不是直接依靠于具体的模块。

中介者形式OC完结类


// 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:&params 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:&params 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:&params 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 的一般过程:

  1. 创立方针方针:首先,需求创立一个或多个方针方针,这些方针包括想要调用的办法。每个方针方针都应该是一个独立的类,并遵从特定的命名规矩。

  2. 完结方针方针的办法:在每个方针方针类中,完结想要调用的办法。保证办法的命名以 “IMP_” 最初,例如 IMP_doSomething:。办法的参数应该是一个 NSDictionary 类型的参数。

  3. 调用方针方针办法:在需求调用方针方针办法的当地,运用 YJHMediatorperformTarget:action:params:shouldCacheTarget: 办法来调用指定方针方针的指定办法。传入方针方针称号、办法称号和参数。依据需求,能够挑选是否缓存方针方针。

  4. 完结调用并处理成果:依据你的需求,能够在调用办法后处理回来的成果。

下面是一个简单的示例,演示怎么运用 YJHMediator

// 创立方针方针类
@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: 办法。然后,咱们通过 YJHMediatorperformTarget:action:params:shouldCacheTarget: 办法调用了 Target_A 类的 doSomething 办法,并传入了一个包括音讯的参数字典。最后,Target_AdoSomething 办法被调用,并输出相应的日志信息。

请注意,这只是一个简单的示例,实际运用中可能涉及更杂乱的业务逻辑和多个方针方针。保证依据你的需求恰当地安排和管理方针方针和办法,并遵从命名规矩以使 YJHMediator 能够正确识别和调用它们。

示例

  1. 创立方针方针:首先,需求创立一个或多个方针方针,这些方针包括想要调用的办法。每个方针方针都应该是一个独立的类,并遵从特定的命名规矩。
  2. 完结方针方针的办法:在每个方针方针类中,完结想要调用的办法。保证办法的命名以 “IMP_” 最初,例如IMP_doSomething:。办法的参数应该是一个NSDictionary类型的参数。
// Target_TTHomeMoudle.h
#import <UIKit/UIKit.h>
typedef void(^TTSearchPresentDidClickBlock)(long long, NSString *);
@interface Target_TTHomeMoudle : NSObject
- (UIViewController *)IMP_TTSearchRoomViewController:(NSDictionary *)dict;
@end
// 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
  1. 调用方针方针办法:在需求调用方针方针办法的当地,运用YJHMediatorperformTarget:action:params:shouldCacheTarget:办法来调用指定方针方针的指定办法。传入方针方针称号、办法称号和参数。依据需求,能够挑选是否缓存方针方针。
  2. 完结调用并处理成果:依据你的需求,能够在调用办法后处理回来的成果。

例如创立一个YJHMediator的分类界说一个办法运用YJHMediatorperformTarget:action:params:shouldCacheTarget:办法来调用指定方针方针的指定办法

// YJHMediator+TTHomeMoudle.h
#import "YJHMediator.h"
#import <UIKit/UIKit.h>
@interface YJHMediator (TTHomeMoudle)
/**
查找控制器
*/
- (UIViewController *)homeMethod_CallName_searchRoomController:(BOOL)isPresent block:(id)block;
@end
// 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