依賴反轉(zhuǎn)(倒置)原則(Dependency inversion principle,DIP)是面向?qū)ο缶幊?大原則之一。這個(gè)原則應(yīng)該是計(jì)算機(jī)開(kāi)發(fā)人員必知必會(huì)的一個(gè)基本原則,但是看了網(wǎng)上很多Blog上貼的解釋(講解、理解等等),發(fā)現(xiàn)很多人對(duì)該原則的理解還是存在一定偏差的。
首先是該原則的含義,下列引用內(nèi)容來(lái)自于維基百科的依賴反轉(zhuǎn)原則詞條:
該原則指一種特定的解耦(傳統(tǒng)的依賴關(guān)系建立在高層次上,而具體的策略設(shè)置則應(yīng)用在低層次的模塊上)形式,使得高層次的模塊不依賴于低層次的模塊的實(shí)現(xiàn)細(xì)節(jié),依賴關(guān)系被顛倒(反轉(zhuǎn)),從而使得低層次模塊依賴于高層次模塊的需求抽象。該原則規(guī)定:
- 高層次的模塊不應(yīng)該依賴于低層次的模塊,兩者都應(yīng)該依賴于抽象接口;
- 抽象接口不應(yīng)該依賴于具體實(shí)現(xiàn)。而具體實(shí)現(xiàn)則應(yīng)該依賴于抽象接口。
網(wǎng)上不少的Blog都有說(shuō)DIP原則,例子也是舉了若干,并且從舉例看貌似也很貼切。不過(guò),這些Blog中基本都是在解釋依賴接口編程如何如何的好,當(dāng)然在他們舉的例子中均能體現(xiàn)出依賴接口編程的好處,這點(diǎn)本人沒(méi)有任何的異議,甚至Blog的行文和案例方面都沒(méi)有可挑剔的,比本人強(qiáng)太多了。但是,DIP中的倒置(習(xí)慣使用倒置,不習(xí)慣反轉(zhuǎn),以后均使用倒置)如何體現(xiàn)?難道依賴接口,不依賴具體實(shí)現(xiàn)就是所謂的“倒置”?顯然這里面還有“事兒”沒(méi)有說(shuō)出來(lái)??戳司W(wǎng)上很多的解釋都讓人很失望,特別是在搜索引擎的第一頁(yè)給出的各個(gè)“文章”中,只有維基百科里面的解釋本人覺(jué)得算比較明確的。下面就說(shuō)說(shuō)所謂的“倒置”問(wèn)題談?wù)勎易约旱恼J(rèn)識(shí)。
個(gè)人感覺(jué)針對(duì)依賴倒置原則,應(yīng)該是在涉及到軟件系統(tǒng)的結(jié)構(gòu)設(shè)計(jì)及實(shí)現(xiàn)時(shí)才能更好的去理解。按現(xiàn)在軟件開(kāi)發(fā)的“行規(guī)”,一個(gè)復(fù)雜的系統(tǒng)必然存在高層與低層,并且,高層對(duì)象使用低層對(duì)象為其提供的“服務(wù)”來(lái)實(shí)現(xiàn)自己的業(yè)務(wù)邏輯,即所謂的高層依賴低層。但如果高層對(duì)象直接使用這些低層對(duì)象(的具體實(shí)現(xiàn)),當(dāng)業(yè)務(wù)變化,而低層的已有實(shí)現(xiàn)無(wú)法滿足高層的服務(wù)需求時(shí),那就需要“傷筋動(dòng)骨”。為了避免這樣的問(wèn)題,人們提出了面向(依賴)接口編程,這樣只要接口不發(fā)生變化,低層的實(shí)現(xiàn)不會(huì)影響上層的使用。目前網(wǎng)上大多數(shù)的Blog基本都說(shuō)到這里就“完結(jié)撒花”了。他們大概、或許、應(yīng)該是認(rèn)為依賴了接口就是“倒置”了。可是細(xì)想一下,如果僅僅是依賴了接口就“撒花”,那為啥這個(gè)原則不叫“依賴接口原則”?這其中的“倒置”究竟是說(shuō)啥?
按照常理,軟件劃分層也好,模塊也厚,通常都是將相同語(yǔ)義的元素放在一起,因此接口與其實(shí)現(xiàn)(類(lèi))應(yīng)該處于一層或模塊之中。如下圖所示(StarUML繪制,請(qǐng)忽略圖片中背景水印,免費(fèi)的還要啥自行車(chē)?):
這看似好像沒(méi)有問(wèn)題,但是軟件的高層應(yīng)用可能會(huì)發(fā)生變化,即來(lái)自客戶的需求會(huì)發(fā)生變化(這是常事兒?。.?dāng)高層的應(yīng)用發(fā)生了改變,那它依賴的低層對(duì)象所提供的服務(wù)也很可能要發(fā)生變化,因?yàn)楦邔右瓿尚碌臉I(yè)務(wù),低層要負(fù)責(zé)提供對(duì)應(yīng)的服務(wù)。那么問(wèn)題來(lái)了,誰(shuí)來(lái)約定這個(gè)接口提供什么樣的服務(wù)?按照前面的邏輯,接口和實(shí)現(xiàn)放在低層中,那應(yīng)該由低層提供,可是低層開(kāi)發(fā)人員并不負(fù)責(zé)高層的應(yīng)用邏輯。低層應(yīng)該應(yīng)該只關(guān)心自己那點(diǎn)事兒,即負(fù)責(zé)響應(yīng)高層的需求,去按照需求提供實(shí)現(xiàn)服務(wù)。但現(xiàn)在接口放在低層維護(hù),就應(yīng)該由低層的開(kāi)發(fā)人員負(fù)責(zé)體現(xiàn)需求的接口的“變更”(提供新的服務(wù))。這樣會(huì)發(fā)現(xiàn)這樣的情況,即負(fù)責(zé)高層實(shí)現(xiàn)的開(kāi)發(fā)人員,他們擁有需求,但無(wú)法定義描述需求的接口;負(fù)責(zé)低層的開(kāi)發(fā)人員,他們不管需求,只應(yīng)提供具體實(shí)現(xiàn),卻要維護(hù)和應(yīng)用需求有關(guān)的接口。這不就出現(xiàn)了很大的矛盾嗎?

因此,為了解決這樣的矛盾,人們提出將本應(yīng)放在低層的接口放在高層,低層的實(shí)現(xiàn)依賴高層提供的接口,去實(shí)現(xiàn)相應(yīng)的服務(wù)(請(qǐng)參見(jiàn)上圖所示)。本人認(rèn)為這才是DIP中“倒置”的真正含義所在。
本文分兩天抽空寫(xiě)的,前一天還能不翻墻直接訪問(wèn)中文的維基百科,今天不翻墻就不行了,白高興了半天。
ps:想吐槽,已無(wú)力,就這么著吧~