前言
??相信在面試中渔伯,只要問到Spring顶霞,基本都會拋出一個問題,說說你對Spring IOC理解吧锣吼?雖然在日常的開發(fā)經(jīng)常會使用到选浑,但是要回答起來,并不簡單玄叠。大腦經(jīng)過簡單的頭腦風暴后古徒,蹦出了控制反轉、依賴注入這樣的詞語读恃。顯然這些并不是面試官想聽的隧膘。
IOC是什么?
??IOC(Inverse of Contro)控制反轉寺惫,有時候也被稱為DI(Dependency injection)依賴注入疹吃,它是一種降低對象耦合關系的一種設計思想。
??2004年西雀,Martin Fowler探討了一個問題萨驶,既然IOC是控制反轉,那么到底是哪些方面的控制被反轉了呢艇肴?篡撵,經(jīng)過詳細地分析和論證后判莉,他得出了答案:獲得依賴對象的過程被反轉了∮控制被反轉之后券盅,獲得依賴對象的過程由自身管理變?yōu)榱擞蒊OC容器主動注入。于是膛檀,他給“控制反轉”取了一個更合適的名字叫做“依賴注入(Dependency Injection)”锰镀。他的這個答案,實際上給出了實現(xiàn)IOC的方法:注入咖刃。所謂依賴注入就是:由IOC容器在運行期間泳炉,動態(tài)地將某種依賴關系注入到對象之中。
??控制反轉(IOC)是一種思想嚎杨,而依賴注入(Dependency Injection)則是實現(xiàn)這種思想的方法花鹅。
我的理解
??假如有這樣一個場景,你一時興起你想玩GTA5
枫浙,這時候你需要先去下載GTA5
刨肃,然后安裝好GTA5
,安裝完以后你就能開心的玩耍了箩帚。玩了一段時間你可以能覺得有點膩了真友,又想玩CS
了,很顯然你又要先去下載紧帕,然后安裝盔然,才能愉快的玩耍。多經(jīng)歷幾次是嗜,你可能就覺得有點煩了愈案,你就在想要是有個游戲倉庫就好了,能自動的幫我下載和安裝游戲鹅搪。這樣我想玩啥站绪,游戲倉庫直接給我就可以了。而IOC
就是這個游戲倉庫涩嚣。
Game
public interface Game {
void download();
void install();
void play();
}
Cs
public class Cs implements Game {
@Override
public void download() {
System.out.println("下載Cs");
}
@Override
public void install() {
System.out.println("安裝Cs");
}
@Override
public void play() {
System.out.println("我在玩Cs");
}
}
Gta5
public class Gta5 implements Game {
@Override
public void download() {
System.out.println("下載GTA5");
}
@Override
public void install() {
System.out.println("安裝GTA5");
}
@Override
public void play() {
System.out.println("GTA5玩的很開心");
}
}
Player
public class Player {
public void play(){
Game game = new Gta5();
game.download();
game.install();
game.play();
}
}
??上面代碼中可以看到Player
和Gta5
(這可以是任意一個實現(xiàn)了Game接口
的類型)之間存在強耦合關系崇众,并且在編譯期間就指定好了掂僵。當Gta5
發(fā)生改變時航厚,Player
也需要做出相應的改變。由于每個玩家玩的游戲都是不一樣的锰蓬,如果要適應需求幔睬,那我們需要不停的進行修改。顯然這是不符合規(guī)范的芹扭。
public class Player {
private Game game;.
public Player(Game game) {
this.game = game;
}
public void play(){
game.play();
}
}
??將Player
的代碼根據(jù)依賴倒置原則
麻顶,程序要依賴于抽象接口赦抖,不要依賴于具體實現(xiàn)進行修改。這樣大大降低了Player
和具體Game的實現(xiàn)類
的耦合度辅肾。這個時候我們可以發(fā)現(xiàn)队萤,原本需要在Player
內對Game
具體實現(xiàn)類進行實例化,現(xiàn)在變成了由外部傳入矫钓。假如我傳個Gat5
進去要尔,他就在玩Gta5
,把Gta5
變成Cs
新娜,他就在玩Cs
了赵辕。Player
不需要進行任何改變。
這個時候概龄,我們再回過頭來看看的定義还惠。
- 控制反轉:獲得依賴對象的過程由自身管理變?yōu)榱擞蒊OC容器主動注入。
- 依賴注入:由IOC容器私杜,在運行期間蚕键,動態(tài)地將某種依賴關系注入到對象之中。
白話一下
??原本呢歪今,我想玩游戲嚎幸,我必須要先去下載好游戲,等到安裝完成以后寄猩,才能開始玩嫉晶。有了游戲倉庫以后,我只需要告訴它田篇,我玩啥游戲就可以了替废,它就會幫我下載并安裝好游戲,等到我想玩的時候就能直接玩了泊柬。
??原本呢椎镣,我需要在Player
內自己的去實例化Game
的實現(xiàn)類。現(xiàn)在呢兽赁,只需要在XML
內配置好相應的依賴關系状答。假如配置的是Gta5
。等到Player
被實例化的時候刀崖,IOC
就會將Gta5
注入進來了惊科。至于Gta5
是如何被實例化的Player
完全不需要關心。
概括一下:就是主動創(chuàng)建對象過程變成了被動接收亮钦,編譯期依賴變成了運行時依賴馆截,從而達到了對象之間的松耦合。
為什么要使用IOC?好處在哪里蜡娶?
??很顯然混卵,IOC的作用是降低對象和對象之間的耦合度,這和我們所期望高內聚窖张,低耦合的設計思想是一致的嘛幕随,所以能降低耦合當然要使用啊。好處有如下幾點:
- 將類實例化的過程透明化宿接,方便調用方使用合陵。
- IOC容器使用單例模式管理對象,效率高澄阳,可以減少內存的占用拥知。當然也通過配置可以實現(xiàn)多例。
- 依賴關系統(tǒng)一管理碎赢,方便修改低剔。
IOC和工廠模式的區(qū)別?
??不知道會不會有小伙伴吐槽肮塞,看了半天IOC不就是個工廠嘛襟齿,都是將類實例化的過程透明化,方便調用方使用枕赵。其實還是有所區(qū)別猜欺。當需求發(fā)生改變的時候,工廠模式需要修改相應的類才能實現(xiàn)拷窜,然而IOC是通過反射機制來實現(xiàn)的开皿,不需要我們重新編譯代碼,因為它的對象都是動態(tài)生成的篮昧。
??舉個簡單的例子赋荆,假如xx類的構造參數(shù)發(fā)生改變了,工廠就必須要修改對應的創(chuàng)建過程懊昨。然而IOC就沒有這個煩惱了窄潭,修改相應的配置就可以了,代碼完全不需要進行改動酵颁。
<bean id="gta5" class="com.hxh.service.impl.Gta5">
<constructor-arg name="username" value="不一樣的科技宅"></constructor-arg>
</bean>
我們可以這樣回答嫉你。
??IOC翻譯過來的意思是控制反轉,也被稱作為依賴注入躏惋。通過將主動創(chuàng)建對象過程變成了被動接收幽污,編譯期依賴變成了運行時依賴,以此來降低對象之間的耦合度其掂。為了實現(xiàn)依賴注入油挥,需要在XML內配置好依賴關系潦蝇,并且將對象實例化款熬,銷毀深寥,等過程統(tǒng)一交由IOC容器進行管理。這樣的話贤牛,由于IOC容器將類的實例化過程透明化惋鹅,并且創(chuàng)建的是單例對象,所以在方便調用方的使用同時殉簸,還減少了內存的占用闰集。
參考文章
結尾
??寫完內心有點忐忑,如果有覺得寫的不對的地方般卑,希望能在評論區(qū)指出來武鲁,感謝。
??如果覺得對你有幫助蝠检,可以多多評論沐鼠,多多點贊哦,也可以到我的主頁看看叹谁,說不定有你喜歡的文章饲梭,也可以隨手點個關注哦,謝謝焰檩。
??我是不一樣的科技宅憔涉,每天進步一點點,體驗不一樣的生活析苫。我們下期見兜叨!