有同學在學習 Spring 框架中可能會問這樣的問題,為什麼通過依賴注入就可以降低程式碼間的耦合呢?我通過 new 生產物件不也可以嗎,不就是一行程式碼的不同,一個是 @Resource 注入,一個是 new 建立,怎麼就降低耦合了?
今天博主就帶大家來一步步剖析這個問題
一、傳統方式建立物件
通常我們是這樣建立物件的
WuliCar wuli = new WuliCar();
wuli.run();
第一天:二明想用一輛車,然後通過 new 搞了一輛五菱榮光,呼叫 run 方法開始使用,車子跑起來了,很高興。
一個月後:二明公司賺錢了,不想開五菱了,想換輛寶馬,接下來二明一頓操作:
BaomaCar baoma = new BaomaCar();
baoma.run();
很好,車子從五菱換成了寶馬,跑起來了,很高興。
半年後:二明公司賺大錢了,二明想搞輛直升機,接下來又一頓操作
ZhiShenJi zhi = new ZhiShenJi();
zhi.fly();
這次改動比較大,寶馬換成直升機,run 換成了 fly。
看到這裡先思考一下,不想往下看,這樣做有什麼問題嗎?
思考時間到,我們接著往下看。
從程式碼看好像沒多大問題,不就改了兩行程式碼嘛,這有啥。你想想,如果你的程式碼中有 1000 個地方都是這麼寫的,你想把寶馬換成直升機豈不是要改 1000 次,run 改成 fly 又要改 1000 次,晚上別想下班了。
二、介面程式設計
經過上次一頓操作,二明加了好幾天班才弄完,二明想想每天這麼搞不得累死,不行,得想想辦法。於是二明腦子一轉了,一想就想到了。我定義好一些方法,大家都按照這個規則來,不就好了。
public interface vehicle {
// 定義一個交通工具介面,有一個 work 方法
void work();
}
寶馬實現這個介面:
public class Baoma implements vehicle {
@Override
public void work() {
System.out.println("寶馬跑起來");
}
}
飛機實現這個介面:
public class ZhiShenJi implements vehicle {
@Override
public void work() {
System.out.println("直升機飛起來");
}
}
經過上面改造後,後面二明想把寶馬換成直升機的時候只需要修改 new 那塊就可以了,省了很多時間
三、工廠方法
利用介面確實好一些了,但是問題還是沒有解決。為了提高內聚性,專職類負責特定的事情,所以我們使用一個類作為工廠類,既能生產 Car 又能生產 ZhiShenJi
class VehicleFactory{
VehicleFactory(){}
public static Vehicle getInstance(String type){
Animal result = null;
if("car".equals(type)){
result = new Car();
}
if("zhishenji".equals(type)){
result = new ZhiShenJi();
}
return result;
}
}
如果有一次我想鍛鍊身體,想騎自行車了,那麼很簡單
class VehicleFactory{
VehicleFactory(){}
public static Vehicle getInstance(String type){
Animal result = null;
if("car".equals(type)){
result = new Car();
}
if("zhishenji".equals(type)){
result = new ZhiShenJi();
}
if("zixingche".equals(type)){
result = new ZiXingChe();
}
return result;
}
}
Vehicle vehicle = VehicleFactory.getInstance("zixingche");
vehicle.work();
這種方法把建立物件的過程交給了一個專業的類(Factory),我只需要告訴他我需要什麼(引數),他就會返回給我正確的物件,只是解決了內聚性的問題,但是他並沒有解決我的宣告語句七零八落的散落在程式中,我還是需要去將引數從car
替換為zixingche
四、反射
後來二明想到一個更絕妙的主意.我在寫程式的時候不告訴工廠我需要什麼,等到執行的時候我再告訴工廠我需要什麼,再利用反射技術給我生產出來不就可以了嗎?二明說幹就幹
Vehicle vehicle = VehicleFactory.getInstance(讀取配置檔案);
vehicle.work();
我想要的:zixingche
zixingche.work();
大功告成,這樣我要什麼,都寫在一個配置檔案中,利用反射技術就可以建立好,這樣我就不用在生產了,下次換車的時候直接去配置檔案中修改就好了,程式碼中不用修改。
對於生產物件這件和業務沒有直接關係的事情,我們已經提取給了專業的工廠,專業的工廠還是根據配置檔案進行的生產,想生產什麼我只需要改一處即可,這就是降低了耦合性(生產物件和業務之間的耦合,讓生產物件對業務的影響降到了最低)。
五、Spring IOC
上面第四點說的那些功能,Spring IOC 已經幫助我們實現了,Spring IOC 就是利用工廠模式+反射實現自動生產物件,管理物件生命週期的功能。降低了程式碼的耦合
總結
- 依賴注入的意思是你需要的東西不是由你建立的,而是第三方,或者說容器提供給你的。這樣的設計符合正交性,即所謂的鬆耦合。
- 依賴注入是呼叫者僅通過宣告某個元件就可以獲得元件的控制權,而對該元件的依賴關係管理、查詢、載入由外部完成。
- 依賴注入就是你不用關心物件的生命週期,什麼時候被建立,什麼時候銷燬,只需直接使用即可,物件的生命週期由提供依賴注入的框架來管理。