十一看家鄉
十一回了趟老家,老家是一個小縣城,最多算個四線城市,人均月工資估計2000——3000左右,房價大概在3800——5000左右。經濟主要靠茶葉、貢菊等農林產品,最近幾年浙江老板來投資開了一些工廠,也提供了一些工作機會。
茶余飯后和家中親戚朋友聊天,話語中透露出生活的艱辛,現在基本是既要從事農業生產勞動,又要去周邊工廠找點零工做,活也不好找,人多工作機會少。有的在工廠有固定工作的,工作時間長,假期少,勞動法里規定的假期福利在這里就是一紙空文,一放假還要去從事農業生產,為的是多賺點錢。
我聽了之后心里久久不能平靜,我從家鄉出來已經有十幾年了,十幾年來這種情況好像一直從未改變,生存依舊是那樣的艱辛,中國的底層勞動人民生活水平還需要提升。唯一改變的,是多了許多房子,那房子又是一座大山。
此時不由想起魯迅的《故鄉》
時候既然是深冬;漸近故鄉時,天氣又陰晦了,冷風吹進船艙中,嗚嗚的響,從篷隙向外一望,蒼黃的天底下,遠近橫着幾個蕭索的荒村,沒有一些活氣。我的心禁不住悲涼起來了。
阿!這不是我二十年來時時記得的故鄉?
.....
我躺着,聽船底潺潺的水聲,知道我在走我的路。我想:我竟與閏土隔絕到這地步了,但我們的后輩還是一氣,宏兒不是正在想念水生么。我希望他們不再像我,又大家隔膜起來……然而
我又不願意他們因為要一氣,都如我的辛苦展轉而生活,也不願意他們都如閏土的辛苦麻木而生活,也不願意都如別人的辛苦恣睢而生活。
他們應該有新的生活,為我們所未經生活過的。
為何需要依賴注入?
假設現在我們有這樣的場景,A類要實現發郵件功能,那么代碼可能會這樣寫:
class A { Mail myMail; public void AMethod()//一個方法 { myMail = new Mail(); myMail.sendMail(); } }
上面代碼中,class A 內的AMethod方法體內直接new Mail() 創建對象,這樣的寫法是有問題的,假如此時由於業務需要,Mail類的構造函數發生了改變,創建對象的時候必須傳參數“sendEmail” ,此時,項目中所有所有 new Mail() 都必須改為 new Mail(sendEmail) :
class A{ Mail myMail; public void AMethod()//一個方法 { String sendEmail = "lisan@163.com"; myMail = new Mail(sendEmail); myMail.sendMail(); } }
如果是小型項目那還好說,如果是大型項目,項目中可能有幾千幾萬個地方都用到了"new Mail()",我們都要一一修改,那么將是一場噩夢。像上面的情況我們稱為:Class A 對 Class Mail 產生了依賴,也可以說他們之間有強耦合。
為了解決上面的問題,我們改一改寫法(工廠模式):
class A{ public void AMethod()//一個方法 { MailFactory mailFactory = new MailFactory(); Mail myMail = mailFactory.getEmail(); myMail.sendMail(); } } class MailFactory{ public Mail getEmail(){ return new Mail(); //String sendEmail = "lisan@163.com"; //return new Mail(sendEmail); } }
從上面的代碼我們可以看出,我們不直接在A里面去創建Mail對象,而是在MailFactory類里的getEmail方法里去創建,A方法體內去調用這個方法獲得對象。如果Mail類的構造函數有所變動,我們只要改MailFactory的getMail方法這一個地方即可,這樣看起來比上一種寫法強多了。但是這樣的寫法也不是完全沒有問題的,假如此時MailFactory的getMail方法要加一個參數(當然這種情況不多見),那么Class A 里為了要加參數,還是要改代碼。耦合依然存在。
根據上面兩種寫法我們可以看出,當某個Java對象(調用者),需要調用另外一個Java對象(被依賴對象)方法時,在傳統模式下有兩種做法:
1、原始做法
調用者主動創建被依賴對象,然后再調用被依賴方法
2、簡單工廠模式
調用者先找到被依賴對象的工廠,然后通過主動通過工廠去獲得被依賴對象,最后再調用被依賴方法。
第一種方法會導致調用者和被依賴對象類的強耦合,非常不利於代碼維護和升級。
第二種方法解決了第一種方法的問題,不會產生強耦合,但是由於去主動通過工廠去獲取被依賴對象,這就會帶來調用組件與被依賴對象工廠的耦合。
為了徹底解決耦合問題,引入依賴注入(控制反轉)設計模式。
依賴注入(控制反轉)
由上面可以看出,第一和第二種方法都是主動獲取被依賴對象,或多或少的會有一些耦合,那么如果調用者不去主動調用被依賴對象呢?改主動調用為被動接收呢?
依賴注入的本質就是改主動為被動,由主動調用請求改為被動接收。
在Java Spring中,被依賴的對象不再由程序員實例化,而是通過Spring容器幫我們new指定實例,並且將實例注入到需要該對象的類中。
使用Spring框架之后,調用者獲取被依賴對象由原來主動獲取變成了被動接受,由於由主動變為被動——於是我們稱之為控制反轉;從Spring容器角度來看,Spring容器負責將被依賴對象賦值給調用者的成員變量——相當於為調用者注入它依賴的實例,所以稱之為依賴注入。
此篇為理論部分,下篇為實踐部分。