IOC是什么?
2019獨角獸企業重金招聘Python工程師標準>>>
Inversion of Control,即反轉控制,或許說為依賴注入更為合適。IoC就是一種設計模式。
?Interface Driven Design接口驅動,接口驅動有很多好處,可以提供不同靈活的子類實現,增加代碼穩定和健壯性等等,但是接口一定是需要實現的,也就是如下語句遲早要執行:AInterface a = new AInterfaceImp(); 這樣一來,耦合關系就產生了,如:
???Class A{
??????AInterface a;
??????A(){}
??????aMethod(){
?????????a = new AInterfaceImp();
??????}
???}
ClassA與AInterfaceImp就是依賴關系,如果想使用AInterface的另外一個實現就需要更改代碼了。當然我們可以建立一個Factory來根據條件生成想要的AInterface的具體實現,即:
???InterfaceImplFactory{
???????AInterface create(Object condition){
???????????if(condition = condA){
???????????????return new AInterfaceImpA();
???????????}elseif(condition = condB){
???????????????return new AInterfaceImpB();
???????????}else{
???????????????return new AInterfaceImp();
???????????}
???????}
???}
通過IoC模式可以徹底解決代碼耦合,它把耦合從代碼中移出去,放到統一的XML文件中,通過一個容器在需要的時候把這個依賴關系形成,即把需要的接口實現注入到需要它的類中,這可能就是“依賴注入”說法的來源了。
IOC模式,系統中通過引入實現了IOC模式的IOC容器,即可由IOC容器來管理對象的生命周期、依賴關系等,從而使得應用程序的配置和依賴性規范與實際的應用程序代碼分開。其中一個特點就是通過文本的配件文件進行應用程序組件間相互關系的配置,而不用重新修改并編譯具體的代碼。
???當前比較知名的IOC容器有:Pico Container、Avalon 、Spring、JBoss、HiveMind、EJB等。
???在上面的幾個IOC容器中,輕量級的有Pico Container、Avalon、Spring、HiveMind等,超重量級的有EJB,而半輕半重的有容器有JBoss,Jdon等。
???可以把IoC模式看做是工廠模式的升華,可以把IoC看作是一個大工廠,只不過這個大工廠里要生成的對象都是在XML文件中給出定義的,然后利用Java 的“反射”編程,根據XML中給出的類名生成相應的對象。從實現來看,IoC是把以前在工廠方法里寫死的對象生成代碼,改變為由XML文件來定義,也就是把工廠和對象生成這兩者獨立分隔開來,目的就是提高靈活性和可維護性。
???IoC中最基本的Java技術就是“反射”編程。反射又是一個生澀的名詞,通俗的說反射就是根據給出的類名(字符串)來生成對象。這種編程方式可以讓對象在生成時才決定要生成哪一種對象。反射的應用是很廣泛的,象Hibernate、String中都是用“反射”做為最基本的技術手段。
???在過去,反射編程方式相對于正常的對象生成方式要慢10幾倍,這也許也是當時為什么反射技術沒有普通應用開來的原因。但經SUN改良優化后,反射方式生成對象和通常對象生成方式,速度已經相差不大了(但依然有一倍以上的差距)。
???IoC最大的好處是什么?因為把對象生成放在了XML里定義,所以當我們需要換一個實現子類將會變成很簡單(一般這樣的對象都是現實于某種接口的),只要修改XML就可以了,這樣我們甚至可以實現對象的熱插撥(有點象USB接口和SCIS硬盤了)。
??IoC最大的缺點是什么?
(1)生成一個對象的步驟變復雜了(其實上操作上還是挺簡單的),對于不習慣這種方式的人,會覺得有些別扭和不?直觀。
(2)對象生成因為是使用反射編程,在效率上有些損耗。但相對于IoC提高的維護性和靈活性來說,這點損耗是微不足道的,除非某對象的生成對效率要求特別高。
(3)缺少IDE重構操作的支持,如果在Eclipse要對類改名,那么你還需要去XML文件里手工去改了,這似乎是所有XML方式的缺憾所在。
IOC實現初探
??IOC關注服務(或應用程序部件)是如何定義的以及他們應該如何定位他們依賴的其它服務。通常,通過一個容器或定位框架來獲得定義和定位的分離,容器或定位框架負責:
?保存可用服務的集合
?提供一種方式將各種部件與它們依賴的服務綁定在一起
?為應用程序代碼提供一種方式來請求已配置的對象(例如,一個所有依賴都滿足的對象),這種方式可以確保該對象需要的所有相關的服務都可用。
現有的框架實際上使用以下三種基本技術的框架執行服務和部件間的綁定:
?類型1 (基于接口): 可服務的對象需要實現一個專門的接口,該接口提供了一個對象,可以從用這個對象查找依賴(其它服務)。早期的容器Excalibur使用這種模式。
?類型2 (基于setter): 通過JavaBean的屬性(setter方法)為可服務對象指定服務。HiveMind和Spring采用這種方式。
?類型3 (基于構造函數): 通過構造函數的參數為可服務對象指定服務。PicoContainer只使用這種方式。HiveMind和Spring也使用這種方式。
====================================================================================
IoC就是Inversion of Control,控制反轉。在Java開發中,IoC意味著將你設計好的類交給系統去控制,而不是在你的類內部控制。這稱為控制反轉。
下面我們以幾個例子來說明什么是IoC
假設我們要設計一個Girl和一個Boy類,其中Girl有kiss方法,即Girl想要Kiss一個Boy。那么,我們的問題是,Girl如何能夠認識這個Boy?
在我們中國,常見的MM與GG的認識方式有以下幾種
1 青梅竹馬; 2 親友介紹; 3 父母包辦
那么哪一種才是最好呢?
青梅竹馬:Girl從小就知道自己的Boy。
public class Girl {
void kiss(){
Boy boy = new Boy();
}
}
然而從開始就創建的Boy缺點就是無法在更換。并且要負責Boy的整個生命周期。如果我們的Girl想要換一個怎么辦?(嚴重不支持Girl經常更換Boy,#_#)
親友介紹:由中間人負責提供Boy來見面
public class Girl {
void kiss(){
Boy boy = BoyFactory.createBoy();
}
}
親友介紹,固然是好。如果不滿意,盡管另外換一個好了。但是,親友BoyFactory經常是以Singleton的形式出現,不然就是,存在于 Globals,無處不在,無處不能。實在是太繁瑣了一點,不夠靈活。我為什么一定要這個親友摻和進來呢?為什么一定要付給她介紹費呢?萬一最好的朋友愛上了我的男朋友呢?
父母包辦:一切交給父母,自己不用費吹灰之力,只需要等著Kiss就好了。
public class Girl {
void kiss(Boy boy){
// kiss boy
boy.kiss();
}
}
Well,這是對Girl最好的方法,只要想辦法賄賂了Girl的父母,并把Boy交給他。那么我們就可以輕松的和Girl來Kiss了。看來幾千年傳統的父母之命還真是有用哦。至少Boy和Girl不用自己瞎忙乎了。
這就是IOC,將對象的創建和獲取提取到外部。由外部容器提供需要的組件。
我們知道好萊塢原則:“Do not call us, we will call you.” 意思就是,You, girlie, do not call the boy. We will feed you a boy。
我們還應該知道依賴倒轉原則即 Dependence Inversion Princinple,DIP
Eric Gamma說,要面向抽象編程。面向接口編程是面向對象的核心。
組件應該分為兩部分,即 Service, 所提供功能的聲明 Implementation, Service的實現
好處是:多實現可以任意切換,防止 “everything depends on everything” 問題.即具體依賴于具體。
所以,我們的Boy應該是實現Kissable接口。這樣一旦Girl不想kiss可惡的Boy的話,還可以kiss可愛的kitten和慈祥的grandmother。
二、IOC的type
IoC的Type指的是Girl得到Boy的幾種不同方式。我們逐一來說明。
IOC type 0:不用IOC
public class Girl implements Servicable {
private Kissable kissable;
public Girl() {
kissable = new Boy();
}
public void kissYourKissable() {
kissable.kiss();
}
}
Girl自己建立自己的Boy,很難更換,很難共享給別人,只能單獨使用,并負責完全的生命周期。
IOC type 1,先看代碼:代碼
public class Girl implements Servicable {
Kissable kissable;
public void service(ServiceManager mgr) {
kissable = (Kissable) mgr.lookup(“kissable”);
}
public void kissYourKissable() {
kissable.kiss();
}
}
這種情況出現于Avalon Framework。一個組件實現了Servicable接口,就必須實現service方法,并傳入一個ServiceManager。其中會含有需要的其它組件。只需要在service方法中初始化需要的Boy。
另外,J2EE中從Context取得對象也屬于type 1。它依賴于配置文件。
IOC type 2:
public class Girl {
private Kissable kissable;
public void setKissable(Kissable kissable) {
this.kissable = kissable;
}
public void kissYourKissable() {
kissable.kiss();
}
}
Type 2出現于Spring Framework,是通過JavaBean的set方法來將需要的Boy傳遞給Girl。它必須依賴于配置文件。
IOC type 3:
public class Girl {
private Kissable kissable;
public Girl(Kissable kissable) {
this.kissable = kissable;
}
public void kissYourKissable() {
kissable.kiss();
}
}
這就是PicoContainer的組件 。通過構造函數傳遞Boy給Girl
PicoContainer container = new DefaultPicoContainer();
container.registerComponentImplementation(Boy.class);
container.registerComponentImplementation(Girl.class);
Girl girl = (Girl) container.getComponentInstance(Girl.class);
girl.kissYourKissable();
參考資料
1 http://www.picocontainer.org/presentations/JavaPolis2003.ppt
http://www.picocontainer.org/presentations/JavaPolis2003.pdf
2 DIP, Robert C Martin, Bob大叔的優秀論文
http://www.objectmentor.com/resources/articles/dip.pdf
3 Dependency Injection 依賴注射,Matrin Fowler對DIP的擴展
http://www.martinfowler.com/articles/injection.html
4 IOC框架
PicoContainer 優秀的IOC框架
http://picocontainer.org/
Avalon
http://avalon.apache.org/
Spring Framework
http://www.springframework.org/
HiveMind
http://jakarta.apache.org/commons/hivemind
轉載于:https://my.oschina.net/u/1462795/blog/272056
總結
- 上一篇: RedHat6.2 x86手动配置LNM
- 下一篇: Telnet远程访问思科交换机、路由器