4. IOS 组件化(蘑菇街的路由+协议式)

为了研究组件化,我们主要是讨论 蘑菇街的路由+协议式中间件

讨论第一种方式,并参考 蘑菇街IOS组件化 ,我们来实现一个可以运行的demo,并讨论优缺点。

路由

MGJRouter 单例,通过 订阅或注册发布或使用 来实现。肯定有点模糊,我们开始代码化。

确定唯一标识

通过mgj://detail?id=:id 注册,通过 mgj://detail?id=5 传递参数,首先我们找到两个url的相同点,下面代码中 我通过一个简单的算法+ (NSString *)keyWithUrlStr:(NSString *)urlStr, 得到一个 唯一标识 mgj_detail_id*, 这样就可以通过map 来注册和使用

  • registerURLPattern:toHandler: 注册
  • openURL: 调用组件
@interface MGJRouter : NSObject
// 可以在 一个统一的地方来注释
//mgj://detail?id=:id
+ (void)registerURLPattern:(NSString *)pattern
                 toHandler:(void(^)(NSDictionary *dic))block;
// 去触发组件的回调
//mgj://detail?id=5
+ (void)openURL:(NSString *)urlStr;
@end

@interface MGJRouter()

@property (nonatomic,strong) NSMutableDictionary * map;

@end

@implementation MGJRouter

- (instancetype)init {
    if (self = [super init]) {
        self.map = [NSMutableDictionary dictionary];
    }
    return self;
}

+ (MGJRouter *)shareManager {
    static dispatch_once_t onceToken;
    static MGJRouter * router = nil;
    dispatch_once(&onceToken, ^{
        if (router == nil) {
            router = [[MGJRouter alloc] init];
        }
    });
    return router;
}

// 可以在 一个统一的地方来注释
+ (void)registerURLPattern:(NSString *)pattern
                 toHandler:(void(^)(NSDictionary *dic))block {
    
    NSString * key = [self keyWithUrlStr:pattern];
    [self shareManager].map[key] = block;
}

// 去触发组件的回调
+ (void)openURL:(NSString *)urlStr {
    
    NSString * key = [self keyWithUrlStr:urlStr];
    NSLog(@"key = %@",key);
    void(^block)(NSDictionary *dic) = [self shareManager].map[key];
    if (block) {
        NSMutableDictionary * param  = nil;
        NSURL * url = [NSURL URLWithString:urlStr];
        NSString * query = url.query;
        if (query.length) {
            NSArray * items = [query componentsSeparatedByString:@"&"];
            param = [NSMutableDictionary dictionary];
            for (NSString * item in items) {
                NSArray * littleItems = [item componentsSeparatedByString:@"="];
                NSString * itemFirst = littleItems.firstObject;
                NSString * itemSecond = littleItems.lastObject;
                if (itemFirst && itemSecond) {
                    param[itemFirst] = itemSecond;
                }
            }
        }
        block(param);
    }
}


//mgj://detail?id=:id
//协议名 mgj
// host detail
// query  id=:id
// 把 mgj://detail?id=:id 和 mgj://detail?id=5 转变成相同的唯一key
+ (NSString *)keyWithUrlStr:(NSString *)urlStr {
    NSURL * url = [NSURL URLWithString:urlStr];
    NSString * query = url.query;
    NSString * queryStr = @"";
    if (query.length) {
        NSArray * items = [query componentsSeparatedByString:@"&"];
        for (NSString * item in items) {
            NSString * itemFirst = [item componentsSeparatedByString:@"="].firstObject;
            queryStr = [queryStr stringByAppendingString:itemFirst];
            queryStr = [queryStr stringByAppendingString:@"*"];
        }
    }
    return [NSString stringWithFormat:@"%@_%@_%@",url.scheme,url.host,queryStr];
}

@end

测试组件

// 注册一个组件(一般在启动的时候去注册)
    [MGJRouter registerURLPattern:@"mgj://detail?id=:id&name=:name" toHandler:^(NSDictionary *dic) {
        NSString * oneId = dic[@"id"];
        NSString * name  = dic[@"name"];
        if (oneId && name) {
            //创建组件,并从字典拿到值
            DetailComposite * detail = [[DetailComposite alloc] init];
            detail.oneId = oneId;
            detail.name  = name;
            // 执行组件的方法
            [detail showComposite];
        }
    }];

    // 外界去调用 执行一个组件
    [MGJRouter openURL:@"mgj://detail?id=5&name=leeDev"];
    // 打印出: showComposite _ id = 5 ; name = leeDev

总结路由功能

其实就是使用 map 来存储 key -> 组件的功能 block ,通过 open 传递参数和key 直接调用这个block,并传递参数。

协议 (协议 - 类)

因为我们组件化,就是为了不暴露 我们的实现类,但是我们可以暴露一些接口,这样其实就是为了 降低耦合。

蘑菇街是通过 ModuleManager 来管理 协议 和 类的关联
主要是两个方法

@interface ModuleManager : NSObject
+ (void)registerClassName:(NSString *)className forProtocolName:(NSString *)protocolName;
+ (Class)classForProtocolName:(NSString *)protocolName;
@end



@interface ModuleManager()

@property (nonatomic,strong) NSMutableDictionary * map;

@end
@implementation ModuleManager


- (instancetype)init {
    if (self = [super init]) {
        self.map = [NSMutableDictionary dictionary];
    }
    return self;
}

+ (ModuleManager *)shareManager {
    static dispatch_once_t onceToken;
    static ModuleManager * router = nil;
    dispatch_once(&onceToken, ^{
        if (router == nil) {
            router = [[ModuleManager alloc] init];
        }
    });
    return router;
}

+ (void)registerClassName:(NSString *)className forProtocolName:(NSString *)protocolName {
    
    [self shareManager].map[protocolName] = className;
}

+ (Class)classForProtocolName:(NSString *)protocolName {
    
    NSString * className = [self shareManager].map[protocolName];
    return NSClassFromString(className);
}

@end

假设需要获取购物车的个数
我们定义一个协议

@protocol MGJCart 
+ (NSInteger)orderCount;
@end

在正在实现类里面去实现这个协议

#import "MGjCart.h"
@interface MGJCartImp : NSObject
@end


@implementation MGJCartImp
+ (NSInteger)orderCount {
    //处理逻辑,并返回结果
    return 40;
}
@end

注册和使用


//注册协议 我们只需要
    [ModuleManager registerClassName:@"MGJCartImp" forProtocolName:@"MGJCart"];
    
    //从class 获取的 ,就是我们 只是把 MGJCart 协议暴露出去
    Class cla = [ModuleManager classForProtocolName:@"MGJCart"];
    NSInteger orderCount = [(id )cla orderCount];
    NSLog(@"orderCount = %@",@(orderCount));
    // 打印出 orderCount = 40

优缺点

优点

  • 降低耦合性,就是组件只是依赖url,而不需要依赖具体的类

缺点

  • 传递 image 等对象类型麻烦,url 不支持
  • 回调block 也很麻烦,是可以通过字典回调出来,但是需要文档写的比较清楚,才能回调出来
  • 协议 - 类的 使用,也是比较繁琐,一般是该类的实例是一个 单例对象,因为调用的都是 + 方法

你可能感兴趣的:(4. IOS 组件化(蘑菇街的路由+协议式))