2. 通過實例理解IOC概念:
實例:《墨攻》電影中有一個場景:當劉德華所飾演的墨者革離到達樑國都城下,城上樑國守軍問道:“來者何人?“劉德華回答道:“墨者革離”。以此場景通過一個java類爲這個“城門叩問”的場景進行編劇。
MoAttract:通過演員安排劇本
public class MoAttack {
public voidcityuGateAsk(){
LiuDeHualdh=newLiuDeHua();//演員直接侵入腳本
ldh.responseAsk("墨者革離");
}
}
在上面代碼註釋處,作爲具體角色飾演者的劉德華直接侵入到劇本中,使劇本和演員直接耦合在一起,如圖:
一個明智的編劇在劇情創作時應該圍繞故事的角色進行,而不應該考慮角色的具體飾演者,這樣纔可能在劇本投拍時自由地遴選任何適合的演員,而非綁定在劉德華一個人身上。
通過以上的分析,知道需要爲蓋劇本主人公革離定義一個接口:
public classMoAttack {
public void cityuGateAsk(){
GeLigeli=newLiuDeHua();//引入革離角色接口
geli.responseAsk("墨者革離");//通過接口開展劇情
}
}
墨攻,革離,劉德華三者的類圖關係:
從上圖中可以看出MoAttrack同時依賴於GeLi接口和LIuDeHua類,並沒有達到所期望的劇本依賴於角色的目的。但是角色最終必須通過具體的演員才能拍攝,如何讓LiuDeHua和劇本無關而又能完成GeLi的具體動作呢?當然是在拍攝時,導演將LiuDeHua安排在GeLi的角色上,導演將劇本、角色、飾演者裝配起來:
通過引入導演,劇本和具體的飾演者解耦了,對應到軟件中,導演像是一個裝配器,將具體的飾演者賦予了劇本的角色。
現在可以反過來理解IoC的概念了。IOC(Inverseof control)的字面意思是控制反轉,它包括兩個內容:一是控制:二是反轉。到底是什麼東西的控制被反轉了呢?對應前面的例子,控制是指選擇GeLi角色扮演者的控制權;反轉是指在這種控制權從《墨攻》劇本中移除,轉交到了導演手中。對於軟件來說,既是某一接口具體實現類的選擇控制權從調用類中移除,轉交給第三方裁決。
因爲IOC不夠開門見山,因此業界曾進行廣泛的討論,最終軟件界的泰斗人物Martin Fowler提出了DI(依賴注入:Dependency Injection)的概念用以代替IoC,即調用類對接口實現類的依賴關係由第三方(容器或者協作類)注入,已移除調用類對接口實現類的依賴。
1. Ioc類型
從注入方法上看,主要可以劃分爲三種類型:構造函數注入、屬性注入和接口注入。
構造函數注入:
public class MoAttack {
private GeLigeli;
public MoAttack(GeLi geli){ //注入革離的具體扮演者
this.geli=geli;
}
public voidcityuGateAsk(){
geli.responseAsk("墨者革離");
}
}
MoAttack的構造函數並不關心具體是誰扮演革離的角色,只要在構造函數中傳入扮演者按劇本要求完成角色功能即可。角色的具體扮演者由導演來安排,如下代碼:
public classDirector {
public void direct(){
GeLigeli=newLiuDeHua();//指定角色的扮演者
MoAttackmoAttack=newMoAttack(geli);//注如具體扮演者到劇本中
moAttack.cityGateAsk();
}
}
屬性注入:
有時,導演會發現,雖然革離是影片《墨攻》的第一主角,但是並非每一個場景都需要革離的出現,在這種情況下通過構造函數並不妥當,這是可以考慮使用屬性注入。屬性注入可以有選擇的通過setter方法完成調用類所需依賴的注入,更加靈活方便。
public classMoAttack {
private GeLigeli;
public void setGeli(GeLi geli) { //屬性注入
this.geli = geli;
}
public void cityGateAsk(){
geli.responseAsk("墨者革離");
}
}
Director通過Setter方法注入革離扮演者:
public classDirector {
public void direct(){
GeLigeli=newLiuDeHua();
MoAttackmoAttack=newMoAttack();
moAttack.setGeli(geli); //調用setter方法注入
moAttack.cityGateAsk();
}
}
接口注入:
將調用類所有注入的方法抽取到一個接口中,調用類實現這一接口規定的注入方法,爲了採用接口注入的方式,聲明一個ActorArrangable接口
public interfaceActorArrangable {
void injectGeli(GeLi geli);
}
MoAttack通過接口方法注入革離扮演者
public classMoAttack implementsActorArrangable{
private GeLigeli;
public void injectGeli(GeLi geli){ //實現接口方法
this.geli=geli;
}
public void cityGateAsk(){
geli.responseAsk("墨者革離");
}
}
Director通過接口方法注入革離扮演者:
public classDirector {
public void direct(){
GeLigeli=newLiuDeHua();
MoAttackmoAttack=newMoAttack();
moAttack.injectGeli(geli);
moAttack.cityGateAsk();
}
}
由於接口注入需要額外聲明一個接口,增加類的數目,而且它的效果和屬性輸入並無本質區別,因此不提倡使用。
http://blog.csdn.net/alex_sym/article/details/8255106