板橋里人 http://www.jdon.com 2004/01/31
分離關(guān)注( Separation of Concerns : SOC)是Ioc模式和AOP產(chǎn)生最原始動(dòng)力,通過(guò)功能分解可得到關(guān)注點(diǎn),這些關(guān)注可以是 組件Components, 方面Aspects或服務(wù)Services。
從GoF設計模式中,我們已經(jīng)習慣一種思維編程方式:Interface Driven Design 接口驅動(dòng),接口驅動(dòng)有很多好處,可以提供不同靈活的子類(lèi)實(shí)現,增加代碼穩定和健壯性等等,但是接口一定是需要實(shí)現的,也就是如下語(yǔ)句遲早要執行:
AInterface a = new AInterfaceImp();
AInterfaceImp是接口A(yíng)Interface的一個(gè)子類(lèi),Ioc模式可以延緩接口的實(shí)現,根據需要實(shí)現,有個(gè)比喻:接口如同空的模型套,在必要時(shí),需要向模型套注射石膏,這樣才能成為一個(gè)模型實(shí)體,因此,我們將人為控制接口的實(shí)現成為“注射”。
Ioc英文為 Inversion of Control,即反轉模式,這里有著(zhù)名的好萊塢理論:你呆著(zhù)別動(dòng),到時(shí)我會(huì )找你。
其實(shí)Ioc模式也是解決調用者和被調用者之間的一種關(guān)系,上述AInterface實(shí)現語(yǔ)句表明當前是在調用被調用者AInterfaceImp,由于被調用者名稱(chēng)寫(xiě)入了調用者的代碼中,這產(chǎn)生了一個(gè)接口實(shí)現的原罪:彼此聯(lián)系,調用者和被調用者有緊密聯(lián)系,在UML中是用依賴(lài) Dependency 表示。
但是這種依賴(lài)在分離關(guān)注的思維下是不可忍耐的,必須切割,實(shí)現調用者和被調用者解耦,新的Ioc模式 Dependency Injection 模式由此產(chǎn)生了, Dependency Injection模式是依賴(lài)注射的意思,也就是將依賴(lài)先剝離,然后在適當時(shí)候再注射進(jìn)入。
Ioc模式(Dependency Injection模式)有三種:
| 第一種類(lèi)型 | 從JNDI或ServiceManager等獲得被調用者,這里類(lèi)似ServiceLocator模式。 | 1. EJB/J2EE 2. Avalon(Apache的一個(gè)復雜使用不多的項目) |
| 第二種類(lèi)型 | 使用JavaBeans的setter方法 | 1. Spring Framework, 2. WebWork/XWork |
| 第三種類(lèi)型 | 在構造方法中實(shí)現依賴(lài) | 1. PicoContainer, 2. HiveMind |
有過(guò)EJB開(kāi)發(fā)經(jīng)驗的人都知道,每個(gè)EJB的調用都需要通過(guò)JNDI尋找到工廠(chǎng)性質(zhì)的Home接口,在我的教程EJB是什么章節中,我也是從依賴(lài)和工廠(chǎng)模式角度來(lái)闡述EJB的使用。
在通常傳統情況下,為了實(shí)現調用者和被調用者解耦,分離,一般是通過(guò)工廠(chǎng)模式實(shí)現的,下面將通過(guò)比較工廠(chǎng)模式和Ioc模式不同,加深理解Ioc模式。
假設有兩個(gè)類(lèi)B 和 C:B作為調用者,C是被調用者,在B代碼中存在對C的調用:
| public class B{ |
實(shí)現comp實(shí)例有兩種途徑:?jiǎn)螒B(tài)工廠(chǎng)模式和Ioc。
工廠(chǎng)模式實(shí)現如下:
| public class B{ public B(){ } |
特點(diǎn):
使用Ioc依賴(lài)性注射( Dependency Injection )實(shí)現Picocontainer如下,B類(lèi)如同通常POJO類(lèi),如下:
| public class B{ |
假設C接口/類(lèi)有有一個(gè)具體實(shí)現CImp類(lèi)。當客戶(hù)端調用B時(shí),使用下列代碼:
| public class client{ |
因此,當客戶(hù)端調用B時(shí),分別使用工廠(chǎng)模式和Ioc有不同的特點(diǎn)和區別:
主要區別體現在B類(lèi)的代碼,如果使用Ioc,在B類(lèi)代碼中將不需要嵌入任何工廠(chǎng)模式等的代碼,因為這些工廠(chǎng)模式其實(shí)還是與C有些間接的聯(lián)系,這樣,使用Ioc徹底解耦了B和C之間的聯(lián)系。
使用Ioc帶來(lái)的代價(jià)是:需要在客戶(hù)端或其它某處進(jìn)行B和C之間聯(lián)系的組裝。
所以,Ioc并沒(méi)有消除B和C之間這樣的聯(lián)系,只是轉移了這種聯(lián)系。
這種聯(lián)系轉移實(shí)際也是一種分離關(guān)注,它的影響巨大,它提供了AOP實(shí)現的可能。
AOP我們已經(jīng)知道是一種面向切面的編程方式,由于Ioc解放自由了B類(lèi),而且可以向B類(lèi)實(shí)現注射C類(lèi)具體實(shí)現,如果把B類(lèi)想像成運行時(shí)的橫向動(dòng)作,無(wú)疑注入C類(lèi)子類(lèi)就是AOP中的一種Advice,如下圖:

通過(guò)下列代碼說(shuō)明如何使用Picocontainer實(shí)現AOP,該例程主要實(shí)現是記錄logger功能,通過(guò)Picocontainer可以使用簡(jiǎn)單一行,使所有的應用類(lèi)的記錄功能激活。
首先編制一個(gè)記錄接口:
| public interface Logging { public void enableLogging(Log log); } |
有一個(gè)LogSwitcher類(lèi),主要用來(lái)激活具體應用中的記錄功能:
| import org.apache.commons.logging.Log; public class LogSwitcher { protected Log m_log; public void enableLogging(Log log) { m_log = log; m_log.info("Logging Enabled"); } } |
一般的普通應用JavaBeans都可以繼承這個(gè)類(lèi),假設PicoUserManager是一個(gè)用戶(hù)管理類(lèi),代碼如下:
| public class PicoUserManager extends LogSwitcher { ..... //用戶(hù)管理功能 ..... //業(yè)務(wù)功能 ..... //業(yè)務(wù)功能 |
注意LogSwitcher中Log實(shí)例是由外界賦予的,也就是說(shuō)即將被外界注射進(jìn)入,下面看看使用Picocontainer是如何注射Log的具體實(shí)例的。
|
Logging logging = (Logging) container.getComponentMulticaster(); |
由上代碼可見(jiàn),通過(guò)使用簡(jiǎn)單一行logging.enableLogging()方法使所有的應用類(lèi)的記錄功能激活。這是不是類(lèi)似AOP的advice實(shí)現?
總之,使用Ioc模式,可以不管將來(lái)具體實(shí)現,完全在一個(gè)抽象層次進(jìn)行描述和技術(shù)架構,因此,Ioc模式可以為容器、框架之類(lèi)的軟件實(shí)現提供了具體的實(shí)現手段,屬于架構技術(shù)中一種重要的模式應用。J道的JdonSD框架也使用了Ioc模式。
聯(lián)系客服