組件化-BeeHive

解耦

BeeHive的核心主要有兩類對(duì)象,一類是Service對(duì)象,第二類是Module對(duì)象。
Service解除依賴的方法是通過Protocol抽象來完成,在使用service對(duì)象的時(shí)候通過BHServiceManager來獲取實(shí)現(xiàn)Protocol的對(duì)象,從而完成方法調(diào)用,不會(huì)依賴具體的對(duì)象類型。而對(duì)于Module解耦是通過事件來實(shí)現(xiàn)的,也可以認(rèn)為是觀察者模式。

Service和Module對(duì)象

Service對(duì)象實(shí)現(xiàn)了某個(gè)protocol的對(duì)象,使用它需要先通過BHServiceManager進(jìn)行注冊(cè),這種對(duì)象的聲明周期一般由調(diào)用方?jīng)Q定,一般來說比較短可能調(diào)用完成就釋放了。還有一類是module類型,這種類型對(duì)象由BeeHive中的BHModuleManager對(duì)象進(jìn)行管理,module對(duì)象也需要在注冊(cè)之后才能使用,一般來說它的聲明周期會(huì)長一些,通常還會(huì)處理app相關(guān)的一些事件,同時(shí)也可以自定義事件和處理自定義事件。

BHModuleProtocol定義了所有被管理起來的module需要實(shí)現(xiàn)的一些方法,但是都是可選實(shí)現(xiàn)。主要是module自己排序相關(guān)的level和priority,剩下的主要是BeeHive中定義的一些app生命周期的事件處理方法。

BHServiceProtocol定義了提供服務(wù)的對(duì)象是否是單例,自定義Service基本上都是繼承自它。

而BeeHive中的其他對(duì)象,基本上都是為這兩種類型的對(duì)象服務(wù)的:

beehive-arch.png

BHServiceManager

這個(gè)類是用來管理service和implemention之間的映射,implemention的初始化也通過它來完成。但是對(duì)implemention的緩存是放在BHContext中,這個(gè)類的實(shí)現(xiàn)也比較簡單。
看一下頭文件,主要的接口就是為了注冊(cè)一個(gè)service和創(chuàng)建service對(duì)象:

@interface BHServiceManager : NSObject

@property (nonatomic, assign) BOOL  enableException;

+ (instancetype)sharedManager;

- (void)registerLocalServices;

- (void)registerService:(Protocol *)service implClass:(Class)implClass;

- (id)createService:(Protocol *)service;
- (id)createService:(Protocol *)service withServiceName:(NSString *)serviceName;
- (id)createService:(Protocol *)service withServiceName:(NSString *)serviceName shouldCache:(BOOL)shouldCache;

- (id)getServiceInstanceFromServiceName:(NSString *)serviceName;
- (void)removeServiceWithServiceName:(NSString *)serviceName;

@end

BHModuleManager

所有的module的管理對(duì)象,提供了module相關(guān)的聲明周期方法: 加載,注冊(cè),注銷以及module自身相關(guān)的元數(shù)據(jù)信息,比如是否已經(jīng)初始化,module的level和prioirty信息(用來對(duì)module進(jìn)行排序)。除了module還會(huì)管理與module相關(guān)的事件。整體上看,其實(shí)這個(gè)對(duì)象核心就是處理各種module的事件。

當(dāng)需要注冊(cè)一個(gè)module的時(shí)候會(huì)對(duì)module進(jìn)行初始化,同時(shí)會(huì)生成module相關(guān)的元數(shù)據(jù)信息存放到BHModuleInfos數(shù)組中。module對(duì)象的維護(hù)是存放在BHModules中,并通過module Level和 module Priority 進(jìn)行排序。然后是注冊(cè)與module關(guān)聯(lián)的事件,這里的事件默認(rèn)主要是系統(tǒng)事件,類似前后臺(tái)的切換,openUrl的事件等。最后一步是如果有必要(通過傳入的參數(shù)來控制) 觸發(fā)一些初始化事件,比如setup,init等事件。事件的管理是通過BHSelectorByEvent字典實(shí)現(xiàn)的,它存放了event和selector的映射,通過event可以查詢selector,再對(duì)module進(jìn)行調(diào)用處理。

以下是BHModuleManager內(nèi)部主要的數(shù)據(jù)存儲(chǔ)的對(duì)象,所有的module,事件信息都通過它們進(jìn)行管理

1)BHModuleInfos里存儲(chǔ)了module對(duì)應(yīng)的類型信息,level和priority信息,以及是否初始化信息,它保證全局同類型的module只有一個(gè)存在。

2)BHModules里存儲(chǔ)了所有的module信息

3)BHModulesByEvent里存儲(chǔ)event和module的映射,主要是為了處理事件發(fā)生時(shí)找到所有對(duì)應(yīng)的module

4)BHSelectorByEvent存儲(chǔ)event和selector的映射,通過事件來查找對(duì)應(yīng)的相應(yīng)函數(shù),進(jìn)行調(diào)用

Module的事件封裝以及參數(shù)傳遞

下面說一下module事件的定義以及封裝,在處理事件的過程中,參數(shù)以及上下文信息如何進(jìn)行封裝和傳遞的。

它通過枚舉定義了所有系統(tǒng)層的事件,比如前后臺(tái)切換,openUrl,app一些生命周期的事件等等。它本身是通過Int來進(jìn)行存儲(chǔ)的,所以用戶可以通過int來定義自己的事件。BHModuleManager會(huì)將傳入的事件參數(shù)封裝到BHContext中,并且通過copy的方式傳給對(duì)應(yīng)的module。而BHContext本身就存儲(chǔ)了各種上下文信息,比如開發(fā)環(huán)境,config信息等。通過它module可以知道當(dāng)前所需要的一些環(huán)境信息。BHContext本身是單例,對(duì)于module而言應(yīng)該是使用copy之后的對(duì)象,避免因?yàn)殄e(cuò)誤的改動(dòng)導(dǎo)致全局的參數(shù)發(fā)生變化影響到其他的module。

Service和Module的區(qū)別, 為什么同時(shí)存在

Service用來創(chuàng)建一些實(shí)現(xiàn)了某些功能接口的對(duì)象,完成某次調(diào)用可能對(duì)應(yīng)的對(duì)象就會(huì)被釋放了,如果調(diào)用頻率高會(huì)緩存到BHContext中。而BHModulesManager管理的對(duì)象它可能是存在比較長的時(shí)間,比如和App的聲明周期一樣,像網(wǎng)絡(luò)庫,廣告SDK等,它和BHServiceManager管理的對(duì)象最大區(qū)別就是生命周期不同,它可能會(huì)參與到App或者自定義的事件中。對(duì)于實(shí)現(xiàn)組件化,常駐內(nèi)存的對(duì)象可以考慮封裝成BHModule對(duì)象,通過BHModuleManager來進(jìn)行管理,而臨時(shí)使用的接口,比如一些數(shù)據(jù)處理對(duì)象,日期格式化對(duì)象(主要是那些只跟某些特定業(yè)務(wù)相關(guān)的對(duì)象,可能退出頁面就用不到了)可以通過Service的方式來進(jìn)行管理。

BHConfig/BHContext/BHWatchDog

BHConfig :對(duì)象是配置對(duì)象,提供了按照類型進(jìn)行存取的功能。

BHContext: 它存儲(chǔ)了Config對(duì)象,開發(fā)環(huán)境信息,以及自定義事件以及參數(shù),service緩存的對(duì)象也存放在這個(gè)對(duì)象之中。

BHWatchDog: 它是用來監(jiān)測(cè)主線程是否卡頓的對(duì)象,發(fā)生卡頓會(huì)打印日志提示。實(shí)現(xiàn)卡頓監(jiān)測(cè)的原理是封裝了一個(gè)子線程,在子線程中有一個(gè)標(biāo)記位。通過子線程不斷的循環(huán)在循環(huán)中派發(fā)一個(gè)handler到主線程中,派發(fā)到主線程中主要做的事情就是處理標(biāo)記位,之后通過設(shè)置的interval讓子線程睡眠對(duì)應(yīng)時(shí)間,睡眠interval秒之后再通過標(biāo)記位來判斷主線程是否發(fā)生了卡頓。如果發(fā)生卡頓,主線程在interval時(shí)間內(nèi)可能來不及處理標(biāo)記位,然后由此推斷出發(fā)生了卡頓。為了防止不必要的額外n次派發(fā),在子線程中增加了信號(hào)量來控制派發(fā)次數(shù),在handler中會(huì)增加信號(hào)量,每次循環(huán)結(jié)束會(huì)通過dispatch_semaphore_wait判斷信號(hào)量是否大于0,否則一直處于等待。

BHRouter路由實(shí)現(xiàn)

BHRouter: 通過URL的方式實(shí)現(xiàn)頁面跳轉(zhuǎn),module的注冊(cè),service注冊(cè),以及對(duì)象方法的調(diào)用。url的格式定義了解析的邏輯,所以格式是固定的:

//url - > com.alibaba.beehive://call.service.beehive/pathComponentKey.protocolName.selector/...?params={}(value url encode)

//url - > com.alibaba.beehive://register.beehive/pathComponentKey.protocolName/...?params={}(value url encode)

//url - > com.alibaba.beehive://jump.vc.beehive/pathComponentKey.protocolName.push(modal)/...?params={}(value url encode)#push

在BHRouter中定義了BHRPathComponent對(duì)象,它可以理解成封裝了某個(gè)pathComponentKey的處理邏輯,如果需要使用BHRPathComponent,需要先注冊(cè),pathComponentKey和Component的關(guān)系會(huì)存放到一個(gè)字典中,后續(xù)在處理url的時(shí)候會(huì)通過pathComponentKey獲取對(duì)應(yīng)的Component進(jìn)行處理。如果對(duì)url的處理邏輯相對(duì)簡單,沒有特別的需求,可以不使用BHRPathComponent。我能想到的復(fù)雜點(diǎn)的處理,比如對(duì)于頁面跳轉(zhuǎn)可能有一些特殊的需求,不僅僅只是首頁跳轉(zhuǎn)到某個(gè)頁,可能是需要支持特定的頁面路徑,這種需求做成統(tǒng)一處理的邏輯是比較困難的,但是如果通過BHRPathComponent封裝起來,url解析那塊的邏輯會(huì)很清晰,不使用BHRPathComponent封裝會(huì)導(dǎo)致if else 或者 switch case邏輯很多不好維護(hù),所以這部分算是比較好的設(shè)計(jì),最常使用的場景和一些復(fù)雜的場景都考慮到了,代碼的邏輯也不會(huì)很復(fù)雜。在調(diào)用openUrl的時(shí)候,可以傳入?yún)?shù),這部分參數(shù)會(huì)和url里的query參數(shù)合并到一起。
在push一個(gè)頁面的時(shí)候,除了需要?jiǎng)討B(tài)創(chuàng)建一個(gè)vc的對(duì)象,還需要把一些參數(shù)傳給vc,這部分是通過kvc對(duì)vc的屬性進(jìn)行賦值,再這之前會(huì)對(duì)參數(shù)進(jìn)行過濾,會(huì)判斷是否有對(duì)應(yīng)的property,不存在的會(huì)從參數(shù)中刪除。

BHRouter本身提供了一種更加解耦的調(diào)用對(duì)象方法以及注冊(cè)service和model的方式,因?yàn)槭羌冏址畊rl的方式。成本在于拼接url需要按照特定規(guī)則,參數(shù)需要序列化成字符串json參數(shù)(這部分很難手寫出來)。如果需要處理頁面跳轉(zhuǎn),是只能通過BHRouter來處理的。

BeeHive和BHAppDelegate

BeeHive封裝了BHServiceManager和BHModuleManager,提供了更加方便調(diào)用的注冊(cè)module以及注冊(cè)service創(chuàng)建service的接口。BHAppDelegate取代原始的Appdelegate,主要是為了更方便的處理App聲明周期相關(guān)的各個(gè)事件,把事件發(fā)送給所有module

reference:

http://liumh.com/2018/10/11/beehive-analysis/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容