組件化-BeeHive

解耦

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

Service和Module對象

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

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

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

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

beehive-arch.png

BHServiceManager

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

@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的管理對象,提供了module相關(guān)的聲明周期方法: 加載俭厚,注冊户魏,注銷以及module自身相關(guān)的元數(shù)據(jù)信息,比如是否已經(jīng)初始化挪挤,module的level和prioirty信息(用來對module進(jìn)行排序)叼丑。除了module還會管理與module相關(guān)的事件。整體上看扛门,其實(shí)這個對象核心就是處理各種module的事件鸠信。

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

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

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

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

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

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

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

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

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

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

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

BHConfig/BHContext/BHWatchDog

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

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

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

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

BHRouter: 通過URL的方式實(shí)現(xiàn)頁面跳轉(zhuǎn)酝掩,module的注冊,service注冊眷柔,以及對象方法的調(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對象,它可以理解成封裝了某個pathComponentKey的處理邏輯镶苞,如果需要使用BHRPathComponent喳坠,需要先注冊,pathComponentKey和Component的關(guān)系會存放到一個字典中茂蚓,后續(xù)在處理url的時候會通過pathComponentKey獲取對應(yīng)的Component進(jìn)行處理壕鹉。如果對url的處理邏輯相對簡單,沒有特別的需求聋涨,可以不使用BHRPathComponent晾浴。我能想到的復(fù)雜點(diǎn)的處理,比如對于頁面跳轉(zhuǎn)可能有一些特殊的需求牍白,不僅僅只是首頁跳轉(zhuǎn)到某個頁脊凰,可能是需要支持特定的頁面路徑,這種需求做成統(tǒng)一處理的邏輯是比較困難的茂腥,但是如果通過BHRPathComponent封裝起來狸涌,url解析那塊的邏輯會很清晰,不使用BHRPathComponent封裝會導(dǎo)致if else 或者 switch case邏輯很多不好維護(hù)最岗,所以這部分算是比較好的設(shè)計(jì)帕胆,最常使用的場景和一些復(fù)雜的場景都考慮到了,代碼的邏輯也不會很復(fù)雜般渡。在調(diào)用openUrl的時候懒豹,可以傳入?yún)?shù),這部分參數(shù)會和url里的query參數(shù)合并到一起驯用。
在push一個頁面的時候歼捐,除了需要動態(tài)創(chuàng)建一個vc的對象,還需要把一些參數(shù)傳給vc晨汹,這部分是通過kvc對vc的屬性進(jìn)行賦值豹储,再這之前會對參數(shù)進(jìn)行過濾,會判斷是否有對應(yīng)的property淘这,不存在的會從參數(shù)中刪除剥扣。

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

BeeHive和BHAppDelegate

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

reference:

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者稳衬。
  • 序言:七十年代末霞捡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子薄疚,更是在濱河造成了極大的恐慌碧信,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件街夭,死亡現(xiàn)場離奇詭異砰碴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)板丽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門呈枉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人檐什,你說我怎么就攤上這事∪蹩ǎ” “怎么了乃正?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長婶博。 經(jīng)常有香客問我瓮具,道長,這世上最難降的妖魔是什么凡人? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任名党,我火速辦了婚禮,結(jié)果婚禮上挠轴,老公的妹妹穿的比我還像新娘传睹。我一直安慰自己,他們只是感情好岸晦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布欧啤。 她就那樣靜靜地躺著,像睡著了一般启上。 火紅的嫁衣襯著肌膚如雪邢隧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天冈在,我揣著相機(jī)與錄音倒慧,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛纫谅,可吹牛的內(nèi)容都是我干的炫贤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼系宜,長吁一口氣:“原來是場噩夢啊……” “哼照激!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盹牧,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤俩垃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后汰寓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體口柳,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年有滑,在試婚紗的時候發(fā)現(xiàn)自己被綠了跃闹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡毛好,死狀恐怖望艺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肌访,我是刑警寧澤找默,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站吼驶,受9級特大地震影響惩激,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蟹演,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一风钻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酒请,春花似錦骡技、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至苟弛,卻和暖如春喝滞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背膏秫。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工右遭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留做盅,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓窘哈,卻偏偏與公主長得像吹榴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子滚婉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容