推薦深度好文:原文鏈接荆忍,作者:張洋
真經(jīng)第六章——運(yùn)作 Moving
“運(yùn)動(dòng)是絕對(duì)的——牛頓”
6.1、導(dǎo)言
在前五章中撤缴,我們從世界觀的這話題開(kāi)始刹枉,逐步引出了抽象、層次屈呕、繼承和耦合微宝。這些內(nèi)容,形成了對(duì)象論中關(guān)于世界的結(jié)構(gòu)體系虎眨。
然而蟋软,要想真正描述一個(gè)世界,僅有結(jié)構(gòu)式不行的嗽桩。開(kāi)始我們說(shuō)過(guò)岳守,世界觀主要關(guān)注兩個(gè)方面:一是世界是什么樣子的(結(jié)構(gòu)),另一個(gè)就是世界時(shí)如何演進(jìn)的(運(yùn)作)÷狄保現(xiàn)在湿痢,我們來(lái)討論對(duì)象論中關(guān)于世界運(yùn)作的理論。
這里首先要指出一點(diǎn)扑庞,“對(duì)象論”是關(guān)于程序世界(即將一個(gè)軟件系統(tǒng)看成一個(gè)世界)的世界觀譬重,而非關(guān)于現(xiàn)實(shí)世界的拒逮,所以,將對(duì)象論應(yīng)用于現(xiàn)實(shí)世界時(shí)臀规,往往會(huì)有所偏頗消恍。其實(shí)前面的某些地方已經(jīng)體現(xiàn)出這一點(diǎn),而在運(yùn)作理論這里以现,會(huì)體現(xiàn)的尤其明顯狠怨。但是為了直觀起見(jiàn),我依然會(huì)將對(duì)象論應(yīng)用于現(xiàn)實(shí)世界去舉例子邑遏,當(dāng)然我會(huì)非常謹(jǐn)慎和小心佣赖,并且會(huì)明確指出對(duì)象論應(yīng)用于現(xiàn)實(shí)世界的偏頗在哪里。
6.2记盒、世界本沒(méi)有類(lèi)
對(duì)象論認(rèn)為:世界的演進(jìn)憎蛤,是而且只是各種對(duì)象通過(guò)互相調(diào)用其他對(duì)象的公開(kāi)服務(wù)而完成交互。
注意纪吮,是對(duì)象交互俩檬,而不是類(lèi)交互!沒(méi)錯(cuò)碾盟,類(lèi)之間是永遠(yuǎn)不可能交互的棚辽。因?yàn)椴徽撌乾F(xiàn)實(shí)世界還是程序世界,從來(lái)不存在具體的類(lèi)冰肴。類(lèi)只是抽象思維作用于對(duì)象的產(chǎn)物屈藐,它幫助我們理解、記憶熙尉、分析和設(shè)計(jì)联逻。類(lèi)是抽象的概念,它“客觀”存在检痰,但不是“具體”的存在包归。
例如,現(xiàn)實(shí)世界中铅歼,我們可以找出很多個(gè)“具體的蘋(píng)果”對(duì)象公壤,但是你能找出一個(gè)東西,說(shuō)它是“蘋(píng)果”這個(gè)類(lèi)嗎谭贪?你這一輩子吃的每一個(gè)蘋(píng)果境钟,都是一個(gè)具體的蘋(píng)果對(duì)象锦担,從來(lái)沒(méi)有具體的“蘋(píng)果類(lèi)”和你交互過(guò)俭识。再上升一點(diǎn),你一生交互過(guò)的所有東西洞渔,都是對(duì)象套媚,而沒(méi)有一個(gè)具體的類(lèi)缚态。“類(lèi)”不過(guò)是你的抽象思維作用于對(duì)象形成的幫助你理解認(rèn)識(shí)世界的抽象概念罷了堤瘤∶德“類(lèi)們”從不曾和你真正交互。
程序世界中也是一樣本辐,程序運(yùn)行起來(lái)桥帆,從來(lái)都是具體對(duì)象之間的交互,類(lèi)只是幫助你分析設(shè)計(jì)的概念工具罷了慎皱。
認(rèn)識(shí)到上面幾點(diǎn)對(duì)于理解對(duì)象論的世界運(yùn)行理論非常重要老虫,時(shí)刻銘記,參與真正世界運(yùn)行的茫多,只有對(duì)象祈匙,沒(méi)有類(lèi)!對(duì)象在世界中天揖,類(lèi)在我們心中夺欲!
這一小節(jié)的標(biāo)題是“世界本沒(méi)有類(lèi)”,代表兩個(gè)意思:一是世界“本來(lái)”沒(méi)有類(lèi)今膊,二是世界“本質(zhì)”沒(méi)有類(lèi)些阅。
你可能會(huì)問(wèn),在第五章“耦合”中斑唬,不是說(shuō)依賴關(guān)系是“兩個(gè)類(lèi)因?yàn)榭赡芙换ザa(chǎn)生的關(guān)系”嗎扑眉?其實(shí),確切點(diǎn)說(shuō)赖钞,應(yīng)該是“兩個(gè)類(lèi)所能映射到的對(duì)象因?yàn)榭赡芙换ザa(chǎn)生的關(guān)系”腰素,本質(zhì)上,依賴本來(lái)是對(duì)象間的依賴雪营,只不過(guò)在抽象時(shí)被同時(shí)抽象到類(lèi)里面了弓千。
6.3、程序世界——大同的和諧世界
雖然在對(duì)象論里献起,現(xiàn)實(shí)世界和抽象世界的基本運(yùn)作機(jī)理是一樣的洋访,但程序世界和現(xiàn)實(shí)世界在具體運(yùn)作上有很大差別。首先谴餐,我要告訴你姻政,程序世界時(shí)多么的大同和和諧!
程序世界與現(xiàn)實(shí)世界第一點(diǎn)區(qū)別:現(xiàn)實(shí)世界的依賴以對(duì)象為單位岂嗓,程序世界的依賴以類(lèi)為單位汁展。
沒(méi)明白這意味著什么?
舉個(gè)例子,在現(xiàn)實(shí)世界中食绿,是不是關(guān)系很重要啊侈咕。為什么?因?yàn)槟阏J(rèn)識(shí)的人多器紧,可依賴的人就多耀销。例如你生病了,如果你有個(gè)醫(yī)生朋友铲汪,看病就方便很多熊尉;如果你要打官司,而你又恰巧認(rèn)識(shí)律師朋友掌腰,是不是很爽呢帽揪;如果你想上清華大學(xué),剛好清華大學(xué)校長(zhǎng)是你親戚辅斟,那一切就好辦多了是吧转晰。
為什么會(huì)這樣?究其本質(zhì)士飒,是因?yàn)?b>現(xiàn)實(shí)世界中對(duì)象間的依賴是以對(duì)象為單位的查邢,這種依賴關(guān)系不會(huì)隨著泛化過(guò)程而被泛化到類(lèi)里面去。例如酵幕,有一個(gè)人現(xiàn)在在北京航空航天大學(xué)上學(xué)扰藕,從這“一個(gè)人可”以泛化出“人”這個(gè)類(lèi),而北航可以泛化出“大學(xué)”這個(gè)類(lèi)芳撒,但這個(gè)具體的人和北航的這種關(guān)系可沒(méi)有被泛化到兩個(gè)類(lèi)中邓深,也就是說(shuō),并不是每一個(gè)“人對(duì)象”都可以去任何一個(gè)“大學(xué)對(duì)象”去上學(xué)的笔刹。
不過(guò)芥备,如果是程序世界里,上面的推理是可行的舌菜,因?yàn)?b>程序世界中對(duì)象間的依賴是以類(lèi)為單位的萌壳,這種依賴關(guān)系會(huì)隨著泛化過(guò)程而被泛化到類(lèi)里面去。并且日月,只要兩個(gè)類(lèi)建立了依賴袱瓮,那么兩個(gè)類(lèi)之間的所有對(duì)象都兩兩依賴了。換句話說(shuō)爱咬,在程序世界里尺借,只要有一個(gè)“人”和一個(gè)“大學(xué)”發(fā)生了聯(lián)系,那么這種聯(lián)系就被泛化到類(lèi)中了精拟,隨后燎斩,所有的“人”都可以上“任何”的大學(xué)虱歪。
圖6.1、兩個(gè)世界中依賴的區(qū)別
看圖6.1瘫里,假設(shè)世界上只有三個(gè)人和三所大學(xué)实蔽。在現(xiàn)實(shí)世界中荡碾,小龍女考上了清華谨读,不過(guò)這和其他人其他大學(xué)一點(diǎn)關(guān)系也沒(méi)有,這種關(guān)系并沒(méi)有體現(xiàn)在類(lèi)上坛吁,看劳殖,兩個(gè)類(lèi)沒(méi)有任何聯(lián)系。但在程序世界中拨脉,小龍女考上了清華哆姻,一下子人和大學(xué)兩個(gè)類(lèi)就關(guān)聯(lián)起來(lái)了,接著玫膀,張無(wú)忌和郭靖這兩個(gè)不好好學(xué)習(xí)的學(xué)生也沾了光矛缨,和三所大學(xué)都聯(lián)系起來(lái)了。(提示:其實(shí)這里和第四章講到的OCP和LSP聯(lián)系非常緊密帖旨,讀者可以聯(lián)系OCP和LSP兩個(gè)原則自己思考一下為什么程序世界會(huì)這樣箕昭。)
你知道了吧,在程序世界里解阅,全世界的醫(yī)生隨你看落竹,律師隨你用,大學(xué)隨你上货抄,美食隨你吃述召!多么和諧大同的美好世界!
看了上面對(duì)程序世界的描述蟹地,你是不是已經(jīng)垂涎三尺了积暖?恨不得自己變成一段代碼,跑到程序世界里怪与。不過(guò)別著急呀酸,事情也許沒(méi)有你想象的那么美好。下面我們來(lái)看另一個(gè)程序世界與現(xiàn)實(shí)世界的區(qū)別琼梆。
6.4性誉、程序世界——封建的專制世界
上文描述了程序世界是多么多么美好,不過(guò)如果有一天茎杂,你真的跑到里面去了错览,你可就慘了。不信看下面煌往。話說(shuō)你一進(jìn)程序世界倾哺,就迫不及待想在程序世界里找個(gè)漂亮的女朋友轧邪,可以嗎?對(duì)不起羞海,不成忌愚!你想吃法國(guó)大餐,對(duì)不起却邓,不成硕糊!你想上最好的大學(xué),對(duì)不起腊徙,不成简十!……搞什么!不是說(shuō)程序世界什么都可以得到嗎撬腾。沒(méi)錯(cuò)螟蝙,除了選擇權(quán)!
程序世界里的對(duì)象沒(méi)有選擇權(quán)民傻。
為什么會(huì)這樣胰默?因?yàn)槿绻麑?duì)象有選擇權(quán),就沒(méi)法貫徹OCP了漓踢!你要是活在程序世界里牵署,不但給你包辦婚姻,連吃飯彭雾、上學(xué)……一切的一切碟刺,你都得服從包辦,對(duì)象一點(diǎn)點(diǎn)選擇權(quán)也沒(méi)有薯酝。至于誰(shuí)給你包辦的半沽,那是后話。
看了這些吴菠,你還敢去程序世界嗎者填?不過(guò)這還不是最恐怖的,告訴你更恐怖的一點(diǎn):
程序世界里的對(duì)象不認(rèn)識(shí)對(duì)象做葵。
沒(méi)錯(cuò)占哟,良好的面向?qū)ο筇岢珜?duì)象不認(rèn)識(shí)對(duì)象!很不可思議酿矢?其實(shí)榨乎,這就是所謂的“低耦合”,我們喊了那么多年的“低耦合”瘫筐,到底什么是低耦合蜜暑?所謂低耦合,就是先剝奪對(duì)象的選擇權(quán)策肝,再剝奪對(duì)象的感覺(jué)肛捍。對(duì)象間誰(shuí)也不認(rèn)識(shí)誰(shuí)隐绵,只知道對(duì)象能提供什么服務(wù)。
我們現(xiàn)在了解了程序世界是什么樣子了拙毫,下面依许,我們討論程序世界為什么要這樣。
6.5缀蹄、有奶就是娘
中國(guó)有句俗語(yǔ)峭跳,叫“有奶就是娘”,往往用來(lái)諷刺那種六親不認(rèn)袍患,兩面三刀坦康,誰(shuí)給好處就跟誰(shuí)的無(wú)恥小人竣付。不過(guò)诡延,面向?qū)ο罂墒欠浅L岢坝心叹褪悄铩钡男袨椤H绻覀兊某绦蚨寄茏龅健坝心叹褪悄铩钡牡夭焦诺ǎ蔷驼媸菍?shí)現(xiàn)了“低耦合”這一教義了肆良,套用梁朝偉的話,在程序世界里逸绎,有奶就是娘的行為“是美德”惹恃。
要理解上述道理,我們要先拋卻我們腦中的道德棺牧、廉恥等概念巫糙,從本質(zhì)上看看“有奶就是娘”體現(xiàn)了什么哲學(xué)道理。
“有奶就是娘”颊乘,純從字面解釋参淹,是說(shuō)任何一個(gè)人,只要能給奶喝乏悄,就當(dāng)做自己親娘浙值。上升到哲學(xué)層面,是說(shuō)這么一個(gè)意思:不以其他對(duì)象實(shí)體本身為交互準(zhǔn)則檩小,而以其他對(duì)象的行為作為交互準(zhǔn)則开呐,與一個(gè)對(duì)象是否進(jìn)行交互純粹是從其行為判斷,而不對(duì)對(duì)象本體有任何概念规求。
這種處事哲學(xué)筐付,在現(xiàn)實(shí)生活中是最被人鄙夷的,但在程序世界里確是最提倡的阻肿。如果一個(gè)程序世界里瓦戚,所有對(duì)象都能以“有奶就是娘”的哲學(xué)去處事,那么冕茅,這就是一個(gè)最美好運(yùn)作方式伤极。
6.6蛹找、接口橫空出世
上文說(shuō)到,程序世界中提倡的運(yùn)作方式是“有奶就是娘”的方式哨坪,但要真正實(shí)現(xiàn)這種方式庸疾,似乎還少點(diǎn)東西。我們回顧一下当编,世界本來(lái)只有對(duì)象届慈,我們從對(duì)象中抽象出了類(lèi),這就是目前我們眼中的世界忿偷。這樣金顿,我們的交互,要么以對(duì)象為準(zhǔn)則鲤桥,要么以類(lèi)為準(zhǔn)則揍拆。
以對(duì)象為準(zhǔn)則,顯然是不行的茶凳,因?yàn)槲覀冋f(shuō)了嫂拴,對(duì)象間根本互不認(rèn)識(shí)。以類(lèi)為準(zhǔn)則贮喧,理論上可行筒狠,但這樣有問(wèn)題,就是類(lèi)本身是對(duì)象“實(shí)體的抽象”箱沦,是為了更好記憶辩恼、描述和認(rèn)識(shí)世界而創(chuàng)建的對(duì)象,歸根到底谓形,還是“實(shí)體”范疇的概念灶伊,所以在哲學(xué)上還是和“以行為作為交互準(zhǔn)則”向左。
認(rèn)識(shí)到以上困難套耕,就能認(rèn)識(shí)到谁帕,目前我們的世界還無(wú)法實(shí)現(xiàn)以行為為交互準(zhǔn)則,于是冯袍,我們需要為世界再衍生一些內(nèi)容匈挖。第二章說(shuō)過(guò),世界本身只有對(duì)象康愤,而衍生其他概念的基本方法是抽象儡循。所以,這里我們當(dāng)然要用抽象衍生一些概念出來(lái)征冷。進(jìn)一步择膝,類(lèi)是對(duì)象“實(shí)體”的抽象,而我們需要的是以行為為交互準(zhǔn)則检激,很自然的肴捉,我們完全可以創(chuàng)建一種新概念腹侣,這種概念是行為的抽象,這種新概念齿穗,就是接口(Interface)傲隶。
接口(Interface):對(duì)象行為的抽象。
這里要說(shuō)明窃页,接口和類(lèi)雖然都是從對(duì)象上通過(guò)抽象衍生出的概念跺株,但兩者本質(zhì)不同,是從對(duì)象的兩個(gè)不同的哲學(xué)角度和動(dòng)機(jī)脖卖,抽象出的不同概念乒省,并形成世界兩個(gè)完全不同的方面(Aspect)。至于兩者具體有什么區(qū)別畦木,下一小節(jié)詳細(xì)討論袖扛。
6.7、接口 vs 抽象類(lèi)
經(jīng)常有朋友迷惑一件事情馋劈,抽象類(lèi)和接口有什么區(qū)別攻锰?何時(shí)使用抽象類(lèi)晾嘶,何時(shí)使用接口妓雾?但從功能來(lái)講,抽象類(lèi)完全可以代替接口垒迂,那為什么還要有接口呢械姻?這一小節(jié)來(lái)分析這些問(wèn)題。
這里附帶說(shuō)一個(gè)問(wèn)題机断,產(chǎn)生這種疑惑的原因楷拳,大多是因?yàn)榕笥褌円呀?jīng)習(xí)慣了學(xué)習(xí)一個(gè)東西時(shí),只看其什么樣子吏奸?怎么用欢揖?而不習(xí)慣于弄清楚一個(gè)東西起源于哪?出現(xiàn)的動(dòng)機(jī)是什么奋蔚?其實(shí)她混,要想學(xué)好、用好任何一個(gè)東西泊碑,后兩個(gè)問(wèn)題更關(guān)鍵一些坤按。
舉個(gè)例子,有人發(fā)明了吹風(fēng)機(jī)馒过,我們?nèi)绻桓闱宄涫鞘裁礃幼印坝袀€(gè)把手臭脓,有個(gè)吹風(fēng)筒”,以及怎么用——“打開(kāi)按鈕能吹出熱風(fēng)腹忽,關(guān)閉按鈕就停止了”来累。如果我們只搞清楚這些砚作,那么我們八成用不對(duì)這個(gè)東西,為什么嘹锁?因?yàn)槲覀兏静恢肋@東西是怎么來(lái)的偎巢,它為什么要被發(fā)明出來(lái)。也許我們天天拿他吹臉取暖或吹衣服兼耀,還一派洋洋得意以為用的很好的樣子压昼。殊不知這東西其實(shí)是用來(lái)吹頭發(fā)幫助頭發(fā)快點(diǎn)干起來(lái)的。
不要笑瘤运,這種事經(jīng)常發(fā)生在我們身上窍霞。因?yàn)樵谲浖_(kāi)發(fā)中,有太多的東西拯坟,我們只顧著學(xué)習(xí)其是什么樣子但金,怎么個(gè)用法,也許就像吹風(fēng)機(jī)一樣郁季,這些并不復(fù)雜冷溃,然后我們就把它用到不該用的地方,還以為自己用得很好梦裂。
用不用得好吹風(fēng)機(jī)似枕,不在于是否熟練掌握開(kāi)開(kāi)關(guān)關(guān),而在于是不是用它吹頭發(fā)年柠。同理凿歼,任何東西用得好不好,不在于是不是熟練掌握用法冗恨,而在于是不是用對(duì)了地方答憔。而要想用對(duì)地方,就要弄清楚這個(gè)東西的“怎么出來(lái)的”和“出來(lái)是做什么用的”掀抹。
說(shuō)了挺多虐拓,我們回到接口和抽象類(lèi)的話題上來(lái)。
首先要說(shuō)明一點(diǎn)傲武,“抽象類(lèi)(Abstract Class)”和“類(lèi)(Class)”在哲學(xué)意義上沒(méi)什么區(qū)別蓉驹,其區(qū)別僅僅是實(shí)現(xiàn)層面上的,即抽象類(lèi)只不過(guò)是一種特殊的類(lèi)谱轨,編程環(huán)境強(qiáng)制不準(zhǔn)這種類(lèi)生成實(shí)例戒幔,哲學(xué)意義上兩者沒(méi)有任何區(qū)別。所以土童,從哲學(xué)層面討論“抽象類(lèi)與接口對(duì)比”和討論“類(lèi)與接口對(duì)比”是等價(jià)的诗茎。
類(lèi)與接口的不同點(diǎn)有以下幾點(diǎn):
I. 抽象范疇不同。類(lèi)是對(duì)象“體征”的抽象,接口是對(duì)象行為的抽象敢订。
II. 抽象動(dòng)機(jī)不同王污。抽象出類(lèi)是為了幫助記憶、認(rèn)識(shí)世界楚午,抽象出接口是為了實(shí)現(xiàn)低耦合交互昭齐。
III. 關(guān)注不同。類(lèi)關(guān)注共同的體征矾柜,接口關(guān)注用來(lái)交互的行為阱驾。
IV. 存在范疇不同。類(lèi)存在于抽象層次樹(shù)上怪蔑,接口存在于接口網(wǎng)里覆。
V. 應(yīng)用范疇不同。類(lèi)應(yīng)用于結(jié)構(gòu)范疇缆瓣,是靜態(tài)概念喧枷,接口應(yīng)用于運(yùn)作范疇,是動(dòng)態(tài)概念弓坞。
上面的條目有點(diǎn)學(xué)術(shù)了隧甚,通俗說(shuō)來(lái),類(lèi)是從對(duì)象實(shí)體的的體征范疇上抽象出來(lái)的渡冻,用來(lái)幫助我們記憶戚扳、分析世界不同的對(duì)象,主要表明對(duì)象“什么樣子”菩帝;而接口是從對(duì)象交互時(shí)需要的行為中抽象出來(lái)的咖城,關(guān)注對(duì)象交互時(shí)需要的行為。
還是舉個(gè)例子吧呼奢。
例如,有一群具體的司機(jī)和好多輛具體的汽車(chē)切平,我們可以從司機(jī)中抽象出“司機(jī)”這個(gè)類(lèi)握础,從汽車(chē)抽象出“汽車(chē)”這個(gè)類(lèi),這種抽象是“體征范疇”的悴品,抽象的目的僅僅是幫助記憶禀综、認(rèn)識(shí),完全和交互沒(méi)有關(guān)系苔严。而當(dāng)考慮到交互——司機(jī)需要駕駛汽車(chē)定枷,于是抽象出一個(gè)“可駕駛”這個(gè)接口。注意届氢,一但“可駕駛”這個(gè)接口被抽象出來(lái)欠窒,就完全和司機(jī)以及汽車(chē)沒(méi)有關(guān)系了,除了汽車(chē)退子,拖拉機(jī)岖妄、輪船型将、飛機(jī)都可以實(shí)現(xiàn)這個(gè)接口,而不一定是司機(jī)荐虐,會(huì)開(kāi)車(chē)的任何人都可以通過(guò)“可駕駛”這個(gè)接口去駕駛?cè)魏螌?shí)現(xiàn)“可駕駛”接口的東西七兜。這樣一來(lái),“駕駛”這種交互就完全取決于這個(gè)接口了福扬,這就是“以行為為交互準(zhǔn)則的意思”腕铸。
如果明白了這一小節(jié)的內(nèi)容,相信大家再也不會(huì)被“接口和類(lèi)有什么區(qū)別铛碑?”恬惯、“何時(shí)使用抽象類(lèi),何時(shí)使用接口亚茬?”這樣的問(wèn)題迷惑了酪耳,而可以揮灑自如的在系統(tǒng)中正確使用接口和類(lèi)。一個(gè)方法:拿不準(zhǔn)的時(shí)候問(wèn)問(wèn)自己刹缝,這個(gè)抽象是體征抽象還是行為抽象碗暗?是為了記憶、分析梢夯、設(shè)計(jì)還是為了交互需要言疗?想明白,再下手颂砸。
6.8噪奄、依賴是如何被倒置的
弄清楚了接口,下面可以談一個(gè)有名的OO原則了:依賴倒置原則(DIP)人乓。
如上勤篮,我們先不說(shuō)DIP是什么,而是搞清楚DIP的來(lái)龍去脈色罚。到時(shí)碰缔,朋友們自然對(duì)DIP就有深刻理解了。我們開(kāi)始戳护!
首先金抡,我們要說(shuō)明,依賴是有方向的腌且,客戶類(lèi)依賴于服務(wù)類(lèi)梗肝。什么是客戶類(lèi)?如果A類(lèi)需要B類(lèi)提供的服務(wù)铺董,那么A類(lèi)就依賴B類(lèi)巫击,反之不成立。在沒(méi)有引入接口前,客戶類(lèi)“知道”服務(wù)類(lèi)喘鸟,而服務(wù)類(lèi)“不知道”客戶類(lèi)匆绣,就像下面這個(gè)樣子。
圖6.2什黑、沒(méi)有接口的依賴
我們看到崎淳,司機(jī)作為客戶類(lèi),汽車(chē)作為服務(wù)類(lèi)愕把。依賴的方向是從司機(jī)到汽車(chē)拣凹,以為這里司機(jī)要使用汽車(chē)提供的“駕駛”方法操作汽車(chē)。這是我們不推薦的方式恨豁,因?yàn)椴粔颉八神詈稀毕怠S谑牵覀儗Ⅰ{駛抽象成接口橘蜜,依賴變成如下形式菊匿。
圖6.3、引入接口后的依賴
如圖6.3所示计福,我們從這種交互關(guān)系中跌捆,抽象出了“可駕駛”這個(gè)接口。注意象颖,此時(shí)兩者誰(shuí)也不依賴誰(shuí)佩厚,或說(shuō)誰(shuí)也不知道誰(shuí)了。那么為什么司機(jī)可以放心呢说订?因?yàn)樗揽神{駛接口的存在至壤,他要駕駛的東西一定實(shí)現(xiàn)了這個(gè)接口奸笤,甭管是什么轿秧,只要實(shí)現(xiàn)了這個(gè)接口桥嗤,我就能駕駛。其實(shí)這里才體現(xiàn)出接口的哲學(xué)意義埃叭。
接口的哲學(xué)意義:對(duì)客戶類(lèi)的保證摸恍,對(duì)服務(wù)類(lèi)的約束。
正是接口約束了服務(wù)類(lèi)必須實(shí)現(xiàn)什么功能赤屋,客戶類(lèi)才可以在不知道具體服務(wù)類(lèi)的情況下“放心”進(jìn)行交互,因?yàn)榻涌趯?duì)客戶類(lèi)提供了一種保證壁袄。希望各位能好好體會(huì)接口的這種哲學(xué)意義类早,這對(duì)于對(duì)象論的良好運(yùn)行體質(zhì)的理解非常重要。
可是嗜逻,這樣還不夠涩僻,我們還有一個(gè)非常重要的問(wèn)題沒(méi)有討論:誰(shuí)有權(quán)利定義接口?或者說(shuō)服務(wù)類(lèi)和客戶類(lèi)誰(shuí)擁有接口?當(dāng)然逆日,理論上時(shí)誰(shuí)擁有都可以嵌巷,但卻會(huì)對(duì)世界的運(yùn)作產(chǎn)生巨大影響。我們先看服務(wù)類(lèi)擁有接口的情形室抽。
圖6.4搪哪、服務(wù)類(lèi)擁有接口
如圖6.4,由于服務(wù)類(lèi)擁有制定接口的權(quán)利坪圾,所以各個(gè)服務(wù)類(lèi)都定義了自己的接口晓折,一般情況下他們的接口是不相容的。如圖兽泄,司機(jī)可以駕駛汽車(chē)漓概,但由于輪船、飛機(jī)各自有自己的可駕駛接口病梢,所以會(huì)開(kāi)汽車(chē)未必會(huì)開(kāi)飛機(jī)和輪船胃珍,如果要開(kāi)飛機(jī)或輪船還要一個(gè)個(gè)學(xué),現(xiàn)實(shí)世界中就是這樣一種情況蜓陌。所以觅彰,這種世界的運(yùn)行其實(shí)接口幾乎沒(méi)有起到作用,由于服務(wù)類(lèi)是“大爺”护奈,所以它們可以指定諸多霸王條款缔莲,而客戶必須忍氣吞聲去遷就,所以霉旗,實(shí)際的依賴方向還是從客戶類(lèi)到服務(wù)類(lèi)痴奏。
下面在看看客戶類(lèi)擁有接口會(huì)是什么樣子。
圖6.5厌秒、客戶類(lèi)擁有接口
看上圖读拆,客戶終于翻身做主人了,現(xiàn)在客戶擁有定義接口的權(quán)利鸵闪,服務(wù)類(lèi)必須無(wú)條件實(shí)現(xiàn)檐晕,這下好了,只要會(huì)開(kāi)汽車(chē)蚌讼,就會(huì)開(kāi)輪船和飛機(jī)辟灰,因?yàn)榭蛻粲袡?quán)利定義一個(gè)統(tǒng)一的接口,服務(wù)類(lèi)必須無(wú)條件實(shí)現(xiàn)篡石!這樣芥喇,三種交通工具的駕駛方法必須完全一致(雖然現(xiàn)實(shí)世界還沒(méi)有這樣),這回客戶終于可以揚(yáng)眉吐氣凰萨,體會(huì)一把“顧客是上帝”的感覺(jué)了继控。
在圖6.5的情況下械馆,司機(jī)可以有權(quán)定義接口,他不必“知道”服務(wù)類(lèi)武通,而服務(wù)類(lèi)必須“知道”客戶定義了什么接口霹崎,你有沒(méi)有發(fā)現(xiàn),依賴的方向已經(jīng)悄悄倒置過(guò)來(lái)了冶忱!變成服務(wù)類(lèi)依賴客戶類(lèi)了(誰(shuí)知道誰(shuí)尾菇,誰(shuí)就依賴誰(shuí))!這就是“依賴倒置”的由來(lái)朗和。不必說(shuō)错沽,所謂依賴倒置原則就是讓我們必須按圖6.5的方式運(yùn)行世界,而不能按圖6.2眶拉,6.3千埃,6.4的方式。下面正式定義依賴倒置原則忆植。
依賴倒置原則(DIP):客戶類(lèi)和服務(wù)類(lèi)都應(yīng)該依賴于抽象(接口)放可,并且客戶類(lèi)擁有接口。
我想朝刊,看過(guò)上述來(lái)龍去脈耀里,已經(jīng)不用我再去解釋這個(gè)原則了吧。
6.9拾氓、神秘的統(tǒng)治者
到目前為止冯挎,我們基本已經(jīng)搞清楚了對(duì)象世界的運(yùn)行機(jī)制。但仍有一個(gè)疑問(wèn):我們?cè)?jīng)說(shuō)過(guò)咙鞍,程序世界里對(duì)象時(shí)沒(méi)有選擇權(quán)的房官,甚至不知道誰(shuí)是誰(shuí),只知道接口续滋,那么翰守,誰(shuí)來(lái)指定服務(wù)類(lèi)呢?
例如疲酌,上述司機(jī)可以制定接口蜡峰,所以汽車(chē)、飛機(jī)朗恳、輪船等可駕駛的東西都要實(shí)現(xiàn)湿颅,于是司機(jī)可以按照自己制定的方式駕駛東西。但是粥诫,司機(jī)不能選擇駕駛什么啊肖爵,他根本不知道自己駕駛的是什么,那么臀脏,誰(shuí)制定他是駕駛飛機(jī)劝堪、汽車(chē)還是輪船呢?
似乎冥冥中揉稚,這個(gè)世界存在一個(gè)統(tǒng)治者秒啦,它掌管所有對(duì)象之間誰(shuí)和誰(shuí)交互(只要不違反接口),否則搀玖,世界根本沒(méi)法正常運(yùn)行余境。沒(méi)錯(cuò),程序世界是有這么一個(gè)統(tǒng)治者灌诅,他就是大名鼎鼎的“依賴注入容器(DI)”芳来,也有人叫做“控制反轉(zhuǎn)容器(IoC)”。
什么叫依賴注入猜拾?什么叫控制反轉(zhuǎn)即舌?如果你看了上面的文章,那太好理解了挎袜,依賴注入就是容器挑選符合接口的服務(wù)類(lèi)為客戶類(lèi)提供服務(wù)顽聂。例如,上面司機(jī)要一個(gè)可駕駛的東西盯仪,容器就會(huì)根據(jù)既定規(guī)則選擇一個(gè)紊搪,可能是飛機(jī)、可能是汽車(chē)全景、也可能是輪船耀石,交給司機(jī)。司機(jī)駕駛就行了爸黄,不用管是什么滞伟,反正知道這東西肯定實(shí)現(xiàn)了“可駕駛”接口。
讓我們向這個(gè)偉大的統(tǒng)治者致敬吧馆纳,沒(méi)有他诗良,程序世界可真玩不轉(zhuǎn)了(當(dāng)然,如果某個(gè)程序世界不符合DIP甚至沒(méi)接口鲁驶,都是類(lèi)之間依賴鉴裹,那么就不需要依賴注入容器了,不過(guò)這么一來(lái)钥弯,可就是“高耦合”了径荔,是OO所反對(duì)的)。
6.10脆霎、運(yùn)作起來(lái)吧
到了這里总处,根本不用我廢話說(shuō)程序世界時(shí)怎么運(yùn)作的了,因?yàn)樯厦娑家呀?jīng)說(shuō)明白了睛蛛。不過(guò)鹦马,我還是用短短幾句話總結(jié)一下吧胧谈。
一個(gè)符合OO原則的、低耦合的程序世界的運(yùn)作形式是這樣的:首先參與運(yùn)作的本質(zhì)只有對(duì)象荸频,對(duì)象不直接依賴菱肖,沒(méi)有選擇權(quán),互相不知道旭从,而只知道各個(gè)接口稳强。客戶類(lèi)制定接口和悦,對(duì)象間通過(guò)接口交互退疫,形成運(yùn)作。世界的統(tǒng)治者依賴注入容器決定選擇哪個(gè)服務(wù)類(lèi)給客戶類(lèi)使用鸽素。
好了褒繁,關(guān)于程序世界的運(yùn)作哲理就講到這里了,大家可以在腦子里描繪一下上述運(yùn)作情景付鹿,加深印象澜汤。