前面我們講到一些OO和CO的區(qū)別。肯定有人不以為然。什么CO?OO包羅萬象,你所謂的CO也不過是OO的一個(gè)分支而已。
是啊,易經(jīng)也包羅萬象,也許太極圖或者伏羲六十四卦早就可以描述蒸汽機(jī),噴氣戰(zhàn)斗機(jī),計(jì)算機(jī),烤火雞,等等,更何況什么OO,CO呢?
其實(shí),如果把OO當(dāng)作一個(gè)大籮筐,什么都往里裝,自然,我這里要說的也不會(huì)跳出它的藩籬。畢竟我這CO還是用java實(shí)現(xiàn)的呢,歸根結(jié)底,不是還要用class, interface之類的東西亂搞?
而我所談的OO,和老莊不同,不是那么一個(gè)寬泛的概念。實(shí)際上,我說的OO包括兩個(gè)階段。
第一個(gè)階段:
在這個(gè)階段,傳統(tǒng)的“封裝,繼承,多態(tài)”就已經(jīng)被提了出來。
這種看上去很美的非常符合人的直覺的方法被人們很快地接受了。
畢竟,Person, Vehicle, Animal等等做成類是多么直白,vehicle.start(), person.work(), animal.eat()看上去是多么簡單。
人們象吃了善惡果一樣發(fā)現(xiàn)眼睛似乎一下子明亮了,世界看上去竟然那么分明。靠,老子怎么沒早知道有這個(gè)果子?還有沒有?再給兩個(gè)!
但是,真正應(yīng)用到變化莫測的現(xiàn)實(shí)世界,人們逐漸發(fā)現(xiàn)這個(gè)方法不象它看上去那么簡單。多重繼承的困擾,父子類之間的強(qiáng)烈的耦合都造成了巨大的麻煩。
我們經(jīng)常發(fā)現(xiàn),或者父類提供了很多東西,可我根本不需要。或者我想要某個(gè)東西,可是父類偏偏沒有設(shè)想到這個(gè)可能,沒有提供,而父類自作聰明預(yù)先設(shè)計(jì)好的某個(gè)設(shè)施,不但沒用,反而給子類造成麻煩。
于是,四人幫們振臂高呼:不要以為OO就是隨意設(shè)計(jì)你自己的類。你要遵守一定的模式!
于是,二十幾片樹葉被精心編織成一塊遮羞布遮在OO的私處上,我們真的知道了“善惡”。一個(gè)完善的OO道德體系被圣人們建立了起來。
第二個(gè)階段:
模式真的解放了我們嗎?還是我們更糊涂了?曾幾何時(shí),我們開始痛恨singleton,鄙視template method,害怕visitor。
是時(shí)候該反思一下了。我們真的需要“繼承”嗎?“重載”真的很好嗎?
理論界早就在研究subtype和subclass的區(qū)別,我們發(fā)現(xiàn),似乎有必要區(qū)分這兩個(gè)概念,subtype不見得就必須subclass,甚至,連subclass也不一定就非得subtype。
c++陣營里出現(xiàn)了gp的聲音。大有一舉將OO這個(gè)老朽打翻在地的氣勢。模板!到處是模板。我們用模板組合模板,代替了傳統(tǒng)的繼承,一些人甚至做出了一些相當(dāng)技巧性的東西。
java跳了出來,堅(jiān)定地把subtype和subclass分開。于是,我們有了interface。
所謂interface,理論上就是一個(gè)type。它和class不同,type/interface只定義方法的簽名,但是不包含具體數(shù)據(jù)和實(shí)現(xiàn),它只表示:給你這個(gè)類型的對象后,你能用它來做什么。它不包含:這個(gè)類型的對象具體是怎么做某一件事的。
這樣,class代表實(shí)現(xiàn),interface代表規(guī)范。"implements"代表subtype,"extends"是subclass同時(shí)也是subtype。
subtype和subclass被初步地分開了。我們不再僅僅有幾片樹葉來遮擋私出,現(xiàn)在我們還有了bra。
“繼承”的作用被弱化,甚至被反對。要求用接口組合來代替繼承的呼聲日高。確實(shí)仍然有用繼承和template method比較方便的場合,但是這不再對系統(tǒng)的整體架構(gòu)產(chǎn)生影響。“繼承”更多地被用作一種局部的實(shí)現(xiàn)手段,它影響的不再是整個(gè)系統(tǒng)骨架,而是三兩個(gè)本 身就緊密耦合的類。
interface的出現(xiàn)在OO內(nèi)部是一個(gè)決定性的事件——如果不是一個(gè)革命的話。
它進(jìn)一步完善了OO的“職責(zé)分派”體系。功能的“消費(fèi)者”和“提供者”可以被明確地區(qū)分。
消費(fèi)者只看見接口,而看不見類,這樣,留下了一塊切換不同“提供者”的空間。
OO的整體哲學(xué)甚至被上升了一個(gè)高度:我們不再執(zhí)著于用樹形結(jié)構(gòu),漸進(jìn)式地描述世界,因?yàn)槲覀冋J(rèn)識(shí)到這不大可行,世界比我們想象的要復(fù)雜得多。
OO在這個(gè)階段被重新詮釋為:一個(gè)責(zé)任分工體系。
遇到一個(gè)問題,我們通過分析需求,把它分解成互相協(xié)作的子模塊。每個(gè)子模塊有精確定義的職責(zé)。子模塊之間通過精心設(shè)計(jì)的接口來互相通信,在保證最小耦合的基礎(chǔ)上實(shí)現(xiàn)了分工合作。
所謂ioc就是這樣的思想的一種表達(dá)。子模塊需要一個(gè)外部提供的功能時(shí),不是直接去找到某個(gè)具體實(shí)現(xiàn)模塊,而是通過接口把協(xié)議公開出去。這和上帝 他老人家的設(shè)計(jì)有點(diǎn)形似了:夏娃需要生兒子,但是雖然暫時(shí)旁邊只有一個(gè)adam gg,但是夏娃的身體構(gòu)造卻不是僅僅為adam設(shè)計(jì)的,上帝他老人家給夏娃的是一個(gè)跟任何男人都能生兒子的通用接口。
女人這個(gè)模塊的職責(zé)被定義為:跟男人(們)生孩子。
男人這個(gè)模塊的職責(zé)被定義為:跟女人(們)生孩子。
在這種思路成為系統(tǒng)的主導(dǎo)思想的時(shí)候,子模塊的組裝成為了一個(gè)問題。誰負(fù)責(zé)把雞犬相聞(只看見接口),老死不相往來(看不見類)的子模塊最終組合在一起呢?當(dāng)只有adam夏娃的時(shí)候,上帝一努嘴,倆人就睡一起了。但是當(dāng)天下呼呼嚷嚷都是男人女人的時(shí)候,這就不夠效率了。
于是,月下老人就開了一個(gè)ioc容器,來負(fù)責(zé)把這些用ioc方式設(shè)計(jì)的組件們用一種最經(jīng)濟(jì)的方式拉到一起。
但是,有一點(diǎn)從OO的前驅(qū)PO那里開始到現(xiàn)在都沒有變化,那就是,它們始終都是自頂向下的逐漸細(xì)化求精的方法論。
還有一個(gè)不太為人所關(guān)注的共同點(diǎn):他們,PO, OO,都是命令式的。它們都同樣以一個(gè)狀態(tài)機(jī)的狀態(tài)變遷為著眼點(diǎn)來運(yùn)作系統(tǒng)。
回頭看看還在不甘心地吵嚷不休的c++的gp,它真是一個(gè)單獨(dú)的方法論嗎?
它難道不是也通過自頂向下的方法逐步求精?concept-model難道不就是interface-class的另一種表達(dá)形式?它難道不是也 基于狀態(tài)變遷的命令式系統(tǒng)?(meta-programming不是,但是此處我們暫時(shí)不考慮這種生成式編程,因?yàn)樗趃p里面并不算主流)
它難道不是仍然用類來封裝數(shù)據(jù),用方法來實(shí)現(xiàn)行為?
確實(shí),模板因?yàn)閏oncept不是一個(gè)強(qiáng)制性的類型,任何類,只要具有某個(gè)concept要求的函數(shù)簽名(實(shí)際上甚至要求比這個(gè)還要松的),就可以被當(dāng)作實(shí)現(xiàn)這個(gè)concept的一個(gè)model。如此節(jié)省了我們寫adapter的工作。
另外,模板組合也比基于運(yùn)行時(shí)多態(tài),以來gc的接口組合效率高。
但是,這些細(xì)枝末節(jié)并不能qualify一個(gè)單獨(dú)的方法論。
所以,我們認(rèn)為,gp和programming against interface在方法論上殊途同歸,在實(shí)現(xiàn)層面上則各有利弊。
好了,絮絮叨叨這么多,就是要給我所談到和要進(jìn)行比較的“oo”畫一個(gè)圈子,不能說是“權(quán)威定義”,但是,這就是我要談的那個(gè)“OO”。
下一節(jié)開始,我們就可以正式開始看看怎么用CO來解決我前面提出的那個(gè)例子。
與此同時(shí),有心人也可以想想用OO(inheritance-oriented也好,interface-oriented也好)這種自頂向下的方式怎么實(shí)現(xiàn)這個(gè)需求繁雜,甚至有些條款還不確定的例子。
我自己是想不出太好的方法。一大堆if-else我不喜歡,父子類之間混亂的override這種亂倫行為我也有力不從心之感。
是啊,易經(jīng)也包羅萬象,也許太極圖或者伏羲六十四卦早就可以描述蒸汽機(jī),噴氣戰(zhàn)斗機(jī),計(jì)算機(jī),烤火雞,等等,更何況什么OO,CO呢?
其實(shí),如果把OO當(dāng)作一個(gè)大籮筐,什么都往里裝,自然,我這里要說的也不會(huì)跳出它的藩籬。畢竟我這CO還是用java實(shí)現(xiàn)的呢,歸根結(jié)底,不是還要用class, interface之類的東西亂搞?
而我所談的OO,和老莊不同,不是那么一個(gè)寬泛的概念。實(shí)際上,我說的OO包括兩個(gè)階段。
第一個(gè)階段:
- 1。認(rèn)識(shí)到數(shù)據(jù)和行為的統(tǒng)一性。用類來封裝數(shù)據(jù),隱藏?cái)?shù)據(jù),并且對行為建模。這種更高級(jí)的ADT應(yīng)該是OO的最基本形態(tài)。
2。用類繼承的方式來漸進(jìn)式地描述現(xiàn)實(shí)生活中的概念。對概念之間的差別用子類覆蓋父類某一個(gè)方法的途徑來表達(dá)。
在這個(gè)階段,傳統(tǒng)的“封裝,繼承,多態(tài)”就已經(jīng)被提了出來。
這種看上去很美的非常符合人的直覺的方法被人們很快地接受了。
畢竟,Person, Vehicle, Animal等等做成類是多么直白,vehicle.start(), person.work(), animal.eat()看上去是多么簡單。
人們象吃了善惡果一樣發(fā)現(xiàn)眼睛似乎一下子明亮了,世界看上去竟然那么分明。靠,老子怎么沒早知道有這個(gè)果子?還有沒有?再給兩個(gè)!
但是,真正應(yīng)用到變化莫測的現(xiàn)實(shí)世界,人們逐漸發(fā)現(xiàn)這個(gè)方法不象它看上去那么簡單。多重繼承的困擾,父子類之間的強(qiáng)烈的耦合都造成了巨大的麻煩。
我們經(jīng)常發(fā)現(xiàn),或者父類提供了很多東西,可我根本不需要。或者我想要某個(gè)東西,可是父類偏偏沒有設(shè)想到這個(gè)可能,沒有提供,而父類自作聰明預(yù)先設(shè)計(jì)好的某個(gè)設(shè)施,不但沒用,反而給子類造成麻煩。
于是,四人幫們振臂高呼:不要以為OO就是隨意設(shè)計(jì)你自己的類。你要遵守一定的模式!
于是,二十幾片樹葉被精心編織成一塊遮羞布遮在OO的私處上,我們真的知道了“善惡”。一個(gè)完善的OO道德體系被圣人們建立了起來。
第二個(gè)階段:
模式真的解放了我們嗎?還是我們更糊涂了?曾幾何時(shí),我們開始痛恨singleton,鄙視template method,害怕visitor。
是時(shí)候該反思一下了。我們真的需要“繼承”嗎?“重載”真的很好嗎?
理論界早就在研究subtype和subclass的區(qū)別,我們發(fā)現(xiàn),似乎有必要區(qū)分這兩個(gè)概念,subtype不見得就必須subclass,甚至,連subclass也不一定就非得subtype。
c++陣營里出現(xiàn)了gp的聲音。大有一舉將OO這個(gè)老朽打翻在地的氣勢。模板!到處是模板。我們用模板組合模板,代替了傳統(tǒng)的繼承,一些人甚至做出了一些相當(dāng)技巧性的東西。
java跳了出來,堅(jiān)定地把subtype和subclass分開。于是,我們有了interface。
所謂interface,理論上就是一個(gè)type。它和class不同,type/interface只定義方法的簽名,但是不包含具體數(shù)據(jù)和實(shí)現(xiàn),它只表示:給你這個(gè)類型的對象后,你能用它來做什么。它不包含:這個(gè)類型的對象具體是怎么做某一件事的。
這樣,class代表實(shí)現(xiàn),interface代表規(guī)范。"implements"代表subtype,"extends"是subclass同時(shí)也是subtype。
subtype和subclass被初步地分開了。我們不再僅僅有幾片樹葉來遮擋私出,現(xiàn)在我們還有了bra。
“繼承”的作用被弱化,甚至被反對。要求用接口組合來代替繼承的呼聲日高。確實(shí)仍然有用繼承和template method比較方便的場合,但是這不再對系統(tǒng)的整體架構(gòu)產(chǎn)生影響。“繼承”更多地被用作一種局部的實(shí)現(xiàn)手段,它影響的不再是整個(gè)系統(tǒng)骨架,而是三兩個(gè)本 身就緊密耦合的類。
interface的出現(xiàn)在OO內(nèi)部是一個(gè)決定性的事件——如果不是一個(gè)革命的話。
它進(jìn)一步完善了OO的“職責(zé)分派”體系。功能的“消費(fèi)者”和“提供者”可以被明確地區(qū)分。
消費(fèi)者只看見接口,而看不見類,這樣,留下了一塊切換不同“提供者”的空間。
OO的整體哲學(xué)甚至被上升了一個(gè)高度:我們不再執(zhí)著于用樹形結(jié)構(gòu),漸進(jìn)式地描述世界,因?yàn)槲覀冋J(rèn)識(shí)到這不大可行,世界比我們想象的要復(fù)雜得多。
OO在這個(gè)階段被重新詮釋為:一個(gè)責(zé)任分工體系。
遇到一個(gè)問題,我們通過分析需求,把它分解成互相協(xié)作的子模塊。每個(gè)子模塊有精確定義的職責(zé)。子模塊之間通過精心設(shè)計(jì)的接口來互相通信,在保證最小耦合的基礎(chǔ)上實(shí)現(xiàn)了分工合作。
所謂ioc就是這樣的思想的一種表達(dá)。子模塊需要一個(gè)外部提供的功能時(shí),不是直接去找到某個(gè)具體實(shí)現(xiàn)模塊,而是通過接口把協(xié)議公開出去。這和上帝 他老人家的設(shè)計(jì)有點(diǎn)形似了:夏娃需要生兒子,但是雖然暫時(shí)旁邊只有一個(gè)adam gg,但是夏娃的身體構(gòu)造卻不是僅僅為adam設(shè)計(jì)的,上帝他老人家給夏娃的是一個(gè)跟任何男人都能生兒子的通用接口。
女人這個(gè)模塊的職責(zé)被定義為:跟男人(們)生孩子。
男人這個(gè)模塊的職責(zé)被定義為:跟女人(們)生孩子。
在這種思路成為系統(tǒng)的主導(dǎo)思想的時(shí)候,子模塊的組裝成為了一個(gè)問題。誰負(fù)責(zé)把雞犬相聞(只看見接口),老死不相往來(看不見類)的子模塊最終組合在一起呢?當(dāng)只有adam夏娃的時(shí)候,上帝一努嘴,倆人就睡一起了。但是當(dāng)天下呼呼嚷嚷都是男人女人的時(shí)候,這就不夠效率了。
于是,月下老人就開了一個(gè)ioc容器,來負(fù)責(zé)把這些用ioc方式設(shè)計(jì)的組件們用一種最經(jīng)濟(jì)的方式拉到一起。
但是,有一點(diǎn)從OO的前驅(qū)PO那里開始到現(xiàn)在都沒有變化,那就是,它們始終都是自頂向下的逐漸細(xì)化求精的方法論。
還有一個(gè)不太為人所關(guān)注的共同點(diǎn):他們,PO, OO,都是命令式的。它們都同樣以一個(gè)狀態(tài)機(jī)的狀態(tài)變遷為著眼點(diǎn)來運(yùn)作系統(tǒng)。
回頭看看還在不甘心地吵嚷不休的c++的gp,它真是一個(gè)單獨(dú)的方法論嗎?
它難道不是也通過自頂向下的方法逐步求精?concept-model難道不就是interface-class的另一種表達(dá)形式?它難道不是也 基于狀態(tài)變遷的命令式系統(tǒng)?(meta-programming不是,但是此處我們暫時(shí)不考慮這種生成式編程,因?yàn)樗趃p里面并不算主流)
它難道不是仍然用類來封裝數(shù)據(jù),用方法來實(shí)現(xiàn)行為?
確實(shí),模板因?yàn)閏oncept不是一個(gè)強(qiáng)制性的類型,任何類,只要具有某個(gè)concept要求的函數(shù)簽名(實(shí)際上甚至要求比這個(gè)還要松的),就可以被當(dāng)作實(shí)現(xiàn)這個(gè)concept的一個(gè)model。如此節(jié)省了我們寫adapter的工作。
另外,模板組合也比基于運(yùn)行時(shí)多態(tài),以來gc的接口組合效率高。
但是,這些細(xì)枝末節(jié)并不能qualify一個(gè)單獨(dú)的方法論。
所以,我們認(rèn)為,gp和programming against interface在方法論上殊途同歸,在實(shí)現(xiàn)層面上則各有利弊。
好了,絮絮叨叨這么多,就是要給我所談到和要進(jìn)行比較的“oo”畫一個(gè)圈子,不能說是“權(quán)威定義”,但是,這就是我要談的那個(gè)“OO”。
下一節(jié)開始,我們就可以正式開始看看怎么用CO來解決我前面提出的那個(gè)例子。
與此同時(shí),有心人也可以想想用OO(inheritance-oriented也好,interface-oriented也好)這種自頂向下的方式怎么實(shí)現(xiàn)這個(gè)需求繁雜,甚至有些條款還不確定的例子。
我自己是想不出太好的方法。一大堆if-else我不喜歡,父子類之間混亂的override這種亂倫行為我也有力不從心之感。