客戶端模塊化解耦實(shí)踐 - Router

客戶端模塊化解耦實(shí)踐 - Router


背景

隨著業(yè)務(wù)進(jìn)入快速發(fā)展期烫葬,業(yè)務(wù)線拓展迅速荷辕,項(xiàng)目結(jié)構(gòu)變得龐大復(fù)雜缩膝,導(dǎo)致迭代的成本越來(lái)越高。項(xiàng)目的越發(fā)龐大也使得整個(gè)工程編譯時(shí)間越來(lái)越長(zhǎng)。進(jìn)行項(xiàng)目拆分后模塊化運(yùn)行(項(xiàng)目自運(yùn)行躁锁、自管理)是一個(gè)較好的出路,但項(xiàng)目間的復(fù)雜相互引用導(dǎo)致我們無(wú)從下手卵史,而如何去除這些項(xiàng)目間的引用則是今天的主題

產(chǎn)生

首先我們可以整理下現(xiàn)狀战转,我們的碰到的最大問(wèn)題其實(shí)就是項(xiàng)目間雜亂無(wú)章的耦合、引用

actu-structor

針對(duì)這些耦合以躯、依賴槐秧,我們可以簡(jiǎn)單的分析:從理論上來(lái)說(shuō),每個(gè)項(xiàng)目負(fù)責(zé)單獨(dú)的業(yè)務(wù)忧设,應(yīng)該本身就是相互獨(dú)立的存在刁标。但是實(shí)際上,處于同一個(gè)公司業(yè)務(wù)體系中址晕,項(xiàng)目與項(xiàng)目之間不可能真正做到完全的切割膀懈。(公司與公司間都可能存在合作,項(xiàng)目與項(xiàng)目間當(dāng)然就更可能了)

看來(lái)想從業(yè)務(wù)源頭想去除業(yè)務(wù)依賴是不太可能了谨垃,我們只能從我們技術(shù)角度去進(jìn)行項(xiàng)目間耦合启搂、引用的去除了。而其中最關(guān)鍵的一點(diǎn)就是:耦合刘陶、相互依賴 , 而Router的概念正是為了解決這些問(wèn)題而提出的胳赌。

那Router到底是什么呢?

Router是一個(gè)具有收口匙隔、分發(fā)思想的疑苫、用于處理模塊(項(xiàng)目)間直接依賴、調(diào)用的模型纷责。最直接的體現(xiàn)其實(shí)就是一個(gè)約定捍掺、一個(gè)規(guī)則,按照約定碰逸、規(guī)則進(jìn)行解析乡小,而后分發(fā)。

hope-router

發(fā)展

針對(duì)以上的一些問(wèn)題饵史,其實(shí)我們能get到一些關(guān)鍵特性满钟,收口分發(fā)胳喷。

OK,既然關(guān)鍵信息已經(jīng)得到湃番,偽代碼很快就能敲出:

    public static void jump(String rule){
        if(rule){
            gotoBusinessActivity()
            return;
        }
    
        if(rule){
            invokeBusinessFunction();
            return;
        }
    }

Perfect!!! 調(diào)用方便,確實(shí)做到了 收口吭露、分發(fā)

但是隨著業(yè)務(wù)發(fā)展吠撮,弊端顯示的也越發(fā)明顯。仔細(xì)分析過(guò)后讲竿,可以總結(jié)出一些問(wèn)題

膨脹

  • 隨著業(yè)務(wù)的增長(zhǎng)泥兰,膨脹的太厲害弄屡,成千上萬(wàn)行代碼坐落在這個(gè)類中,名副其實(shí)的大雜燴

維護(hù)成本

  • 所有項(xiàng)目均同時(shí)維護(hù)鞋诗,一個(gè)項(xiàng)目改錯(cuò)可能導(dǎo)致其他項(xiàng)目也受到影響
  • if-else的邏輯維護(hù)太復(fù)雜
  • 分發(fā)邏輯是 hardcode 膀捷,一旦錯(cuò)誤將無(wú)法進(jìn)行修改
  • 各項(xiàng)目無(wú)法真正分離

擴(kuò)展

  • 從代碼結(jié)構(gòu)不難看出,這里的分發(fā)實(shí)質(zhì)上是'親力親為'并非真正的分發(fā)削彬,而‘親力親為’是做不到真正的拆分的

從上面幾個(gè)問(wèn)題來(lái)看全庸,其實(shí)收口并不難,如何做好分發(fā)這才是一件難事融痛。

回顧需求與現(xiàn)有的問(wèn)題壶笼,覺(jué)得自己的if-else模型其實(shí)丟了一件事:沒(méi)有抽離出一套統(tǒng)一的流程

那流程怎么定義?

我在設(shè)計(jì)的時(shí)候喜歡類比現(xiàn)實(shí)生活雁刷,而Router也不外乎覆劈。而這個(gè)模型就很有趣了

我想要寄快遞

這個(gè)是我需求,那么該怎么辦呢沛励?最重要的兩點(diǎn)

  1. 地址
  2. 包裹

我只需要給到快遞員地址以及包裹墩崩,那么就會(huì)給我送到(除非地址錯(cuò)了),但是這里要強(qiáng)調(diào)一點(diǎn)侯勉,我寄快遞鹦筹,并不是快遞員來(lái)接受這個(gè)包裹≈访玻快遞員只是铐拐,而真正接收的是所在地址的人。

想到這里其實(shí)就可以梳理出Router的核心生命周期與非核心生命周期了练对。當(dāng)Router把調(diào)用者的意圖轉(zhuǎn)達(dá)給接受者時(shí)就已經(jīng)完成了它的周期. 接下來(lái)的事就是接受者干的了蚓让,跟Router無(wú)關(guān)

invoke

到這里其實(shí)Router的基本框架已經(jīng)確定(因?yàn)榱鞒桃呀?jīng)抽離), 那么剩下的就是具體模塊的事了埋酬。不難分析出Router的兩大核心模塊:規(guī)則處理執(zhí)行器

規(guī)則

通過(guò)模型,我們知道了兩個(gè)必須的東西:地址框全、包裹 ,那對(duì)應(yīng)到程序中無(wú)非就是 目標(biāo)指向坟桅、數(shù)據(jù) 繁莹,再契合到我們當(dāng)前的業(yè)務(wù)場(chǎng)景粘秆,規(guī)則不難提煉出來(lái):

protocol://path?data

是不是很眼熟?其實(shí)就是我們通用url的簡(jiǎn)化版本下隧。其實(shí)重點(diǎn)就三個(gè)信息:

  1. 協(xié)議奢人,用于版本區(qū)分、功能區(qū)分等
  2. 目標(biāo)指向淆院,路徑何乎,意圖的接受者
  3. 數(shù)據(jù),攜帶的數(shù)據(jù)

同樣我們的規(guī)則定義為

tctclient://project/module?key=value

協(xié)議定義完畢了,但是難點(diǎn)來(lái)了: Path的映射如何處理

舉個(gè)例子,Pathhotel/list 支救,但是這個(gè)只是一個(gè)字符串抢野,我真正想要調(diào)用的是 酒店列表 HotelListAction ,如何將 Path目標(biāo)指向 進(jìn)行關(guān)聯(lián)各墨,這是一個(gè)問(wèn)題蒙保。在討論的過(guò)程中,其實(shí)有三種方案:

  1. if-else 直接邏輯關(guān)聯(lián)
  2. 使用 Map 進(jìn)行關(guān)聯(lián)
  3. 使用 xml 進(jìn)行關(guān)聯(lián)

其實(shí)從本質(zhì)上來(lái)說(shuō)欲主,都一樣,都是為了數(shù)據(jù)關(guān)聯(lián)逝嚎。但是在維護(hù)扁瓢、擴(kuò)展上是有區(qū)別的。

if-else 這個(gè)不用說(shuō)补君,直接的引用會(huì)產(chǎn)生的非常復(fù)雜的依賴網(wǎng)引几,而且無(wú)法抽離出分發(fā)這塊,所有的分發(fā)都需要在當(dāng)前環(huán)境下進(jìn)行關(guān)聯(lián)挽铁。

Map & XML的邏輯很像伟桅,都是 path處理類 的對(duì)應(yīng)。但是在維護(hù)和擴(kuò)展性上我們最終選擇了xml, 優(yōu)點(diǎn)很明顯:無(wú)代碼耦合叽掘、可動(dòng)態(tài)更新 楣铁。而MAP的優(yōu)點(diǎn)在于,不需要進(jìn)行數(shù)據(jù)加載更扁,節(jié)省了這一部分的性能盖腕。

執(zhí)行器

執(zhí)行器的概念就好理解多了,當(dāng)一段規(guī)則被解析成可讀的意圖后浓镜,我需要將意圖溃列、數(shù)據(jù)傳遞給接受者,而這個(gè)接受者可能是各個(gè)業(yè)務(wù)所處理的膛薛。因此我需要設(shè)計(jì)一個(gè)接口(不然沒(méi)指向性了)來(lái)進(jìn)行接收听隐,而業(yè)務(wù)部門可通過(guò)實(shí)現(xiàn)這個(gè)接口來(lái)進(jìn)行處理相關(guān)邏輯。

flow1

雖說(shuō)到這里流程基本已經(jīng)結(jié)束哄啄,但是在實(shí)際的業(yè)務(wù)邏輯中會(huì)衍生出一些特殊的邏輯雅任,比如:

我要打開酒店列表,但是有個(gè)要求咨跌,必須是登陸狀態(tài)才可直接進(jìn)入椿访,否則需要先去登陸。

可能僅僅從這一個(gè)需求上來(lái)看虑润,用現(xiàn)在的流程去完成也不難成玫,可以使用兩個(gè)接收者去完成。但是當(dāng)中間衍生的特殊邏輯很多而且可能多個(gè)業(yè)務(wù)都會(huì)需要,那用兩個(gè)(多個(gè))接收者可能就有會(huì)膨脹的很厲害了哭当。那這個(gè)時(shí)候其實(shí)另外一個(gè)概念就產(chǎn)生了 -- 攔截器猪腕。

攔截器

攔截器是當(dāng)一個(gè)規(guī)則產(chǎn)生最終作用前進(jìn)行的一些特殊而通用的邏輯處理。

處理邏輯其實(shí)很像View Touch事件钦勘,當(dāng)一個(gè)Touch事件產(chǎn)生后陋葡,首先是分配(分發(fā)),然后是攔截彻采,最后才是消費(fèi)腐缤。

而我們的攔截器稍有不同的地方是

  1. 攔截器可以多個(gè)
  2. 只有當(dāng)所有攔截器全部滿足(pass)的情況下才會(huì)走到執(zhí)行器(消費(fèi))
  3. 這種攔截器模型可以通過(guò)遞歸來(lái)進(jìn)行實(shí)現(xiàn)
flow-interceptor

拓展

對(duì)于Router框架設(shè)計(jì)到使用到現(xiàn)在已經(jīng)2年多了,業(yè)務(wù)需求等也都基本可以完成肛响、滿足岭粤。也確實(shí)做到了Router框架抽離、流程確定且業(yè)務(wù)邏輯(包括映射關(guān)系)各自維護(hù)特笋。當(dāng)一個(gè)業(yè)務(wù)需求產(chǎn)生時(shí)剃浇,只需要產(chǎn)生一個(gè)新的規(guī)則來(lái)維護(hù)即可。

但是重新審視下目前的框架其實(shí)仍然有很多需要完善的:

  1. 數(shù)據(jù)映射是通過(guò)xml來(lái)映射猎物,那么必然會(huì)帶來(lái)I/O加載的性能開銷
  2. 是否項(xiàng)目調(diào)用需要寫一段很冗長(zhǎng)的規(guī)則虎囚,比如 jump("tctclient://hotel/list"),而這種字符串參數(shù)通常是無(wú)法通過(guò)編譯器去檢查正確與否的

針對(duì)這兩個(gè)問(wèn)題,其實(shí)我們采用的是(插件)工具去完成蔫磨。

Gradle Plugin + Freemarker

在編譯時(shí)進(jìn)行輔助類的建立

  • xml的加載可以在編譯時(shí)直接生成Map關(guān)系維護(hù)淘讥。
  • 冗長(zhǎng)規(guī)則則可以通過(guò)枚舉來(lái)進(jìn)行維護(hù)(枚舉通過(guò)xml生成), 調(diào)用方式則改為jump(Bridge.HOTEL_LIST)

總結(jié)

該篇文章更多的寫的是我在接受到這個(gè)需求時(shí)的心路歷程,每個(gè)人在寫代碼的時(shí)候都有自己的感受堤如。而從設(shè)計(jì)Router中其實(shí)能發(fā)現(xiàn)很多道理

沒(méi)有一個(gè)模型放之四海而皆準(zhǔn)的

比如一開始的 if-else ,當(dāng)業(yè)務(wù)量很小的時(shí)候 , 這可能是一個(gè)非常好的處理方式适揉。而當(dāng)業(yè)務(wù)膨脹,當(dāng)前結(jié)構(gòu)不適用時(shí)需及時(shí)重構(gòu)煤惩。

框架脫離了業(yè)務(wù)那就什么都不是嫉嘀,只有契合業(yè)務(wù)的框架,才是一個(gè)好框架魄揉。

思考比編碼更重要

當(dāng)接受到一個(gè)需求后剪侮,更多的是需要去思考,去設(shè)計(jì)洛退。提煉出核心關(guān)鍵點(diǎn)瓣俯、流程,針對(duì)流程梳理出核心生命周期非核心生命周期很重要

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末兵怯,一起剝皮案震驚了整個(gè)濱河市彩匕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌媒区,老刑警劉巖驼仪,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掸犬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绪爸,警方通過(guò)查閱死者的電腦和手機(jī)湾碎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)奠货,“玉大人介褥,你說(shuō)我怎么就攤上這事〉萃铮” “怎么了柔滔?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)萍虽。 經(jīng)常有香客問(wèn)我睛廊,道長(zhǎng),這世上最難降的妖魔是什么贩挣? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮没酣,結(jié)果婚禮上王财,老公的妹妹穿的比我還像新娘。我一直安慰自己裕便,他們只是感情好绒净,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著偿衰,像睡著了一般挂疆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上下翎,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天缤言,我揣著相機(jī)與錄音,去河邊找鬼视事。 笑死胆萧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的俐东。 我是一名探鬼主播跌穗,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼虏辫!你這毒婦竟也來(lái)了蚌吸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤砌庄,失蹤者是張志新(化名)和其女友劉穎羹唠,沒(méi)想到半個(gè)月后奕枢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肉迫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年验辞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喊衫。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡跌造,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出族购,到底是詐尸還是另有隱情壳贪,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布寝杖,位于F島的核電站违施,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瑟幕。R本人自食惡果不足惜磕蒲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望只盹。 院中可真熱鬧辣往,春花似錦、人聲如沸殖卑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)孵稽。三九已至许起,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間菩鲜,已是汗流浹背园细。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留接校,地道東北人珊肃。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像馅笙,于是被迫代替她去往敵國(guó)和親伦乔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理董习,服務(wù)發(fā)現(xiàn)烈和,斷路器,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • 你治愈了我 你是我的天使 你是我的生命之光 起初我 猶豫不決 我害怕又彷徨 最終我 塵埃落定 我合上我干涸已久的貝...
    半?yún)⒉伙?/span>閱讀 202評(píng)論 0 1
  • 一直想找個(gè)地方些東西皿淋,日記本太麻煩招刹,博客不想用恬试,空間太多人關(guān)注。所以找這么個(gè)清靜地方疯暑,又不知道說(shuō)些什么训柴。那就從此開...
    查生閱讀 230評(píng)論 1 1
  • 在我抱怨幻馁、吐槽、葛優(yōu)癱越锈、懶的時(shí)候仗嗦,總有人把生活過(guò)的活色生香。 雖然知道網(wǎng)絡(luò)上的東西多少是經(jīng)過(guò)美化的甘凭,但看到有些人的...
    橙子園丁閱讀 146評(píng)論 0 0