前端解读控制反转(IOC)
前言
隨著前端承擔的職責越來越重,前端應用向著復雜化、規模化的方向發展。大型項目模塊化是一種趨勢,不可避免模塊之間要相互依賴,此外還有很多第三方包。這樣的話如何去管理這些繁雜的文件,是一個不可避免的話題。此時作為一種已經被實踐證明過的思想模式一直得到大家的青睞,這就是控制反轉(IOC)。
IOC定義
先看一下維基百科上的定義:
控制反轉(Inversion of Control,縮寫為IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。
原則
針對前端來說,接口的概念不那么清晰明了,不像強類型語言。 概念是比較枯燥的,下面結合例子來看一下可能更好理解一點。
目的
根據概念可以看到最主要的目的就是降低耦合,提高擴展性。在深究之前,我們先看下代碼耦合
代碼耦合
所謂耦合,可以如下圖顯示: 比較清晰明了,代碼相互之間的聯系太直接: 假如obj2報錯,那么整個系統也都報錯了。
所以我們的目的就是降低二者之間的耦合度,
結合圖來說比較清晰,
如果兩者不這么直接的發生關系,那么相互影響的概率就小了那么多了。
另外,這是比較少的模塊,常規項目里顯然不僅僅是只有這么少,想象一下多個模塊的場景: 這里除了耦合之外,不同齒輪之間的依賴關系也是個頭疼的問題,迭代個幾個版本之后發現,這是什么東西,一動就有bug。。。。
所以IOC就是來解決上述問題的。 其常見方式是依賴注入和依賴查找。在js領域里面最出名的就是angular中大量使用了依賴注入。文字比較蒼白,我們可以通過例子來看看。
實例
就從nba來說,有那么一些球星,我們想知道他所屬的球隊,那么可能就像下面這個情況:
//球隊信息 class RTeam {constructor(){this.name = '火箭'} } // 球員信息 class Player{constructor(){this.team = new Team()}info(){console.log(this.team.name)} } // 球員ym let ym = new Player() ym.info() // ‘火箭’看起來挺好的,球員player依賴于某個球隊RTeam 當調用的時候主動去加載球隊即可。此時的控制權在player這里。
假如這個時候,球員發生交易了,球隊信息更換了,轉換到team2了。
這時候我們就需要去修改player里的代碼了,因為球員那里直接寫死了對RTeam的依賴,這種可擴展性是很差的。 這不是我們所想要的,需要重新思考下依賴關系處理了。
球員和球隊之間非得這么直接粗暴的發生聯系嗎,
一個球員對應一個球隊的話,未來會發生變化的可能性太大了,畢竟不止一個球隊。
如果兩者之間不直接發生聯系,中間就需要一個中間模塊來負責兩者關系的處理
球員不關注球隊從哪來,只要給到我就行了。
這樣控制權就不是直接落在player這里了,這正是IOC的設計思路。
依據IOC 改進
參照IOC的幾條原則,我們進行下改進。
高層模塊不應該依賴低層模塊。兩個都應該依賴抽象 這里player是高層模塊,直接依賴了球隊這個低級模塊。所以我們將兩者解耦,player不再直接依賴于該team這個class
抽象不應該依賴具體實現,具體實現應該依賴抽象
具體到這里來看我們的player模塊不應該直接依賴具體team,而是通過構造函數將抽象的teaminfo實例傳遞進去,這樣就解耦具體實現。
直接看代碼比較清楚:
// 球隊信息不依賴具體實現 // 面向接口即面向抽象編程 class TeamInfo {constructor(name) {this.name = name} } class Player {// 此處的參數,是teamInfo的一個實例,不直接依賴具體的實例// 面向抽象constructor(team) {this.team = team}info() {console.log(this.team.name)} } // 將依賴關系放到此處來管理,控制權也放到此處 // Player和TeamInfo之間不再有直接依賴 // 原本直接掌握teaminfo控制權的player不再直接依賴 // 將依賴控制,落在此處(第三方模塊專門管理)即為控制反轉 var ym = new Player(new TeamInfo('火箭')) ym.info() var kobe = new Player(new TeamInfo('湖人')) kobe.info()這里發現,TeamInfo和Player之間已經沒有直接關聯了,依賴關系統一放到getTeamInfo中。
所謂控制反轉就如何上面一樣,將依賴的控制權由player轉移到其他地方即我們專門的依賴管理來做了。 這樣再增加一個team3,改動也不大,復用就行了。 其中之間的關系,如下面這個圖: 彼此不直接發生聯系,依賴關系統一在中間模塊來管理,更加清晰。
實現
上面其實就是最簡單的IOC實現了,基于IOC的編程思想,主要有兩種實現方式:依賴注入和依賴查找。依賴查不太常用,常見的是依賴注入。
依賴注入
在js中常見的就是依賴注入。從名字上理解,所謂依賴注入,即組件之間的依賴關系由容器在運行期決定,形象的來說,即由容器動態的將某種依賴關系注入到組件之中。
在RequireJS/AMD的模塊加載器的實現就是基于依賴注入來的,還有大名鼎鼎的angular,其實現也使用了大量的依賴注入。
結束語
關于控制反轉,一句話總結:控制反轉這里控制權從使用者本身轉移到第三方容器上,而非是轉移到被調用者上,這里需要明確不要疑惑。控制反轉是一種思想,依賴注入是一種設計模式。 可能聽起來比較抽象,其實我們平時開發中見到和用到的也是蠻多的,可能原來沒有對應起來罷了。 至于依賴注入,前端領域用到的就更多了,下面我將結合自身實踐翻譯一篇個人認為很好的文章Dependency-injection-in-JavaScript,來進一步深入依賴注入。 至此,個人見解分享完畢,拋磚引玉,希望共同學習進步。更多文章請移步我的博客
總結
以上是生活随笔為你收集整理的前端解读控制反转(IOC)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 层次和约束:项目中使用vuex的3条优化
- 下一篇: 《从零构建前后分离的web项目》准备 -