前言
BeeHive是阿里开源的一个组件化框架工具,其内部是使用Spring框架Service的理念来实现模块解耦的,实际上就是使用protocol-class的方案。另外,在组件化的基础上,BeeHive还增加了一个事件分发的功能来配合使用。
1. 概览
官方文档中的架构图:
从上图可以看出,BeeHive的工作分为两部分:
事件分发
BeeHive本身会监听一些系统事件和应用事件,比如App生命周期、推送、handoff等,当事件发生时,BeeHive将其分发给各个模块,然后各个业务模块就可以在自己的Module类中调用各自的响应方法。
组件化
这部分是指在组件化的情况下,实现模块间调用,也就是说,各个模块是相互解耦的,BeeHive使用protocol-class的方案实现这一点。
2. 事件分发的作用
当一个事件被触发时,其对应的响应方法需要被执行,比如界面更新、数据存储等。在这个过程中,会涉及到响应方法的调用和实现这两部分。
首先需要确定的是响应方法的实现都是由模块来完成的(不属于现有模块的响应方法可以看做是属于一个全局模块),针对调用响应方法的位置,这里就有两种调用方式,一个是直接在事件触发点调用(通常是在AppDelegate),另一个是通过BeeHive将事件分发给各个模块,在具体模块的Module类中调用。
为了对比这两种调用方法的差别,下面以一个例子来说明:
一个场景
用户在spotlight搜索一个关键字testA,点击搜索结果,app需要跳转到模块A中的一个界面;
搜索关键字testB,点击搜索结果,app需要跳到模块B中的一个界面。
在这个场景中,当用户在spotlight中点击一个搜索结果后,会触发一个handoff事件,这个事件会被AppDelegate接受到,可以把AppDelegate当做是事件的触发点。 这个事件期望的响应是,根据点击的搜索结果,跳转到对应的模块界面中。
2.1. 直接调用
直接调用事件的响应方法,代码如下:
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler{
if ([userActivity.activityType isEqualToString:@"com.company.app.moduleA.one"]) {
id<ModuleAServiceProtocol> moduleAService = [[BeeHive shareInstance] createService:@protocol(ModuleAServiceProtocol)];
[moduleAService pushToModuleAOneViewController];
}else if ([userActivity.activityType isEqualToString:@"com.company.app.moduleB.one"]) {
id<ModuleBServiceProtocol> moduleBService = [[BeeHive shareInstance] createService:@protocol(ModuleBServiceProtocol)];
[moduleBService pushToModuleBOneViewController];
}
return YES;
}
上述代码中BeeHive的createService:方法是用来获取对应的模块句柄(下文会具体讲到),使用这个句柄可以直接调用模块的响应方法,跳转到模块对应的界面。
根据userActivity的类型来判断app是跳转到moduleA的界面还是moduleB的界面。
直接调用存在的问题
- 在事件触发点处(AppDelegate)直接调用模块的响应方法,会将事件的响应代码全都堆积在触发点处,当事件的类别越来越多,这个地方会存在许多判断语句,不便于阅读和维护;
- 更重要的是会导致触发点对各个模块产生依赖,继而会影响触发点的稳定性,只要模块稍有改动,触发点也要跟着变动。
- 在执行事件的响应方法的过程中,会涉及到响应方法的调用逻辑和实现逻辑这两部分。响应方法的实现逻辑通常是在模块中完成的,采用第一种方式
- 响应方法的调用逻辑会在触发点处完成,整个事件的处理过程会被分割在触发点和模块这两部分中,当需要对事件的响应逻辑做出变动时,则需要在这两部分同时做出改变。
- 事件触发点一般是位在主工程中,在大型项目中,模块和主工程一般是分开开发的,并且可能是由不同的开发者开发的,一个事件最好不要同时涉及到这两部分,因为这样会导致这两部分存在某种耦合,不易于维护。
2.2. 事件分发
在使用BeeHive之后,BeeHive会监听这些事件,事件触发后,它会遍历已注册模块对应的Module类,然后调用这些类对应的事件响应方法,这样,BeeHive就将一个事件分发给了所有的Module类。
换句话说,就是给每一个需要响应事件的模块都新建一个对应的Module类,在这个Module类中完成对响应方法的调用,这个Module类和模块将由同一个开发者创建和维护。
这样,一个事件的整个响应过程就都是由模块负责,主工程只需要负责事件分发。事件的处理被隔离在模块内部,即便以后需要修改事件的响应逻辑,也只需要改动模块,主工程不需要任何改动。
3. 事件分发的配置过程
3.1. 初始化
BeeHive内部有一个类BHAppDelegate,它的作用就是监听事件的触发,实际项目中的AppDelegate需要继承这个类。
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[BHContext shareInstance].application = application;
[BHContext shareInstance].launchOptions = launchOptions;
[BHContext shareInstance].moduleConfigName = @"BeeHive.bundle/BeeHive";
[BHContext shareInstance].serviceConfigName = @"BeeHive.bundle/BHService";
[BeeHive shareInstance].enableException = YES;
[[BeeHive shareInstance] setContext:[BHContext shareInstance]];
[super application:application didFinishLaunc