起因是這樣的,還記得夏天的時候.再一次上班的路上,和前公司前端大牛閑聊說道Facebook開源的一個庫,里面都是用url作為驅(qū)動,進(jìn)行VC之間的跳轉(zhuǎn).當(dāng)時一知半解,就覺得這樣設(shè)計所有的頁面或者view更像一個組件,可以通過url被拉起來.視圖之間的輪轉(zhuǎn)會變得跟加直接.當(dāng)時想著Facebook的工程師們太高產(chǎn)了.
這事就一直放著了,然后最近無意在微博上看到一個iOS開發(fā)者寫的博客<iOS應(yīng)用架構(gòu)談 組件化方案>突然想起之前那次閑聊時候的話題,引發(fā)了興趣,隨即把大神的幾篇文章都讀了一遍,感觸頗深.起先寫項目的時候從沒考慮過架構(gòu)的問題,就是那么寫也沒想著以后版本遷移,后續(xù)增加模塊,覺得項目理所應(yīng)當(dāng)這么寫.看過博主的文章之后,決定好好學(xué)習(xí)一下設(shè)計模式.
以大神的一篇關(guān)于跳出面向?qū)ο蟮乃枷?-繼承這篇文章結(jié)合最近看的設(shè)計模式的書,簡單梳理一下我的學(xué)習(xí)思路:
首先是繼承,用過的人多知道它有多好用,在基類里面做統(tǒng)一設(shè)置,所有的派生類再也不用謝重復(fù)的代碼.光想想就是爽.可是,東西好用就有它的缺陷,它的缺點也暴露的很明顯:高耦合.
大神在他的博客中舉了個簡單的場景:產(chǎn)品經(jīng)理提出一個需求,需要在首頁,及其的他子頁面寫個搜索框.接到需求的程序員決定從之前寫好的搜索框派生出一個新的:HOME_SEARCH_BAR派生出PAGE_SEARCH_BAR,目前就這么看,完全沒有任何問題,
需求增加,經(jīng)理要求子頁面的搜索需要多一個本地搜索的功能,于是你會在PAGE_SEARCH_BAR增加一個locasearch功能.之后變態(tài)的要求來了.經(jīng)理提出來,把首頁的搜索換一個樣式,但是子頁面的還保持原來的樣子.這個需求看似簡單,但是用繼承的你確知道,有多蛋疼.首頁你需要在基類的初始化里面寫case,隨著項目的進(jìn)展,越來越多的子類,swich case大法慢慢寫吧.
然后別的地方需要用你寫的localsearch功能,卻發(fā)現(xiàn)需要把你所寫的基類全部拿出來,如果你基類里面又引用了別的東西,只能呵呵.
大神在他的博客給出的解決方案是:用組合替代繼承填渠。將Textfield和search模塊拆開金度,然后通過定義好的接口進(jìn)行交互典唇,一般來說可以選擇Delegate模式來交互侯勉。
剛好我在iOS設(shè)計模式里面也看到類似的做法,它取名叫橋接模式.
舉個列子:要模擬實現(xiàn)兩個游戲機的操作,游戲機分別用AB代替.
首先游戲機A和B都有左手邊都有上下左右四個鍵位,右手邊OX兩個按鍵,中間是開始鍵位,其中A在右邊還有一個選擇鍵,B沒有.除了鍵位有少許差別,面板操作幾乎完全一樣.如果你開始打算為每個具體游戲機設(shè)計專用的控制器,那么勢必會有很多冗余.而且可能以后會導(dǎo)致子類游戲機的激增.以后的業(yè)務(wù)也許派生出來的子類可能不需要方向鍵,而是從加速到讀取方向的變化,從而模擬上下左右.
所以最好的做法是把虛擬的控制器和游戲機分離.這樣他們就能獨立的變化.從而不影響對方的代碼.話句話來說,它們是有各自的類層次.兩個層次會有不同的接口,通過對象組合的方法連接起來.它們之間的靜態(tài)結(jié)構(gòu)圖是這樣的:
consoleVC(setCommand)----------->consoleEmulator(接受command)
| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? ? ? ? ? ? ??
| ? ? ? ? ? A游戲機(接受command, 執(zhí)行方法) ? ? ? ? ?B游戲機(接受command,執(zhí)行方法)
| ? ? ? ? ? ? ? ? ? ? ? ? ?
touchVC( [super setCommand] ? 上下左右選擇開始OX)
consoleVC和consoleEmulator分別是虛擬控制器和游戲機的抽象類,這兩個類有不同的接口,在consoleVC中封裝一個隊Emulator的引用.consoleVC的實例可以在抽象層上是用Emulator的實例.這就完成了兩個類的橋接.
Emulator為其子類定制個性化接口,用于處理游戲機的底層指令.
consoleVC有個相對底層的方法,向橋接端再發(fā)送基本命令,它的set方法接受預(yù)先設(shè)定好的command,并通過"接受command"把消息轉(zhuǎn)發(fā)給內(nèi)嵌的Emulator.
我們想讓所有的方法使用父類中的同一個setCommand實現(xiàn),通過super 而不是self發(fā)送消息.通過橋接模式,可以看到組合對象的力量.我們?yōu)閏onsoleEmulator實現(xiàn)的橋接不可能通過直接的繼承來實現(xiàn).
這也是大神所提倡的優(yōu)先使用對象組合的形式而不是繼承.