日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

应用抽象工厂模式自己动手写一个ioc

發(fā)布時(shí)間:2025/6/15 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 应用抽象工厂模式自己动手写一个ioc 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文的作者Danny hui似乎是TTS上的新人,我從Google搜不出一點(diǎn)關(guān)于本人的信息。從通過(guò)本文可以看出他對(duì)模式與IoC有自己獨(dú)到的見(jiàn)解,本文在TTS上引發(fā)很多網(wǎng)友回帖,反響不一。那么我們現(xiàn)在來(lái)看看作者的IoC之路吧。

?

?原文:http://www.theserverside.com/tt/articles/article.tss?l=InjectionwithAbstractFactory

?

簡(jiǎn)介

?

本文重點(diǎn)討論的是DI(依賴注入)結(jié)合設(shè)計(jì)模式中的Abstract Factory(抽象工廠模式)的優(yōu)勢(shì)與弊端。該方式尤其適合以下場(chǎng)合:

l?????????通過(guò)dynamic parameters(動(dòng)態(tài)參數(shù))來(lái)建立一個(gè)local stateful對(duì)象

l?????????當(dāng)創(chuàng)建對(duì)象時(shí)拋出了checked exception時(shí)進(jìn)行相應(yīng)處理,

l?????????動(dòng)態(tài)的封裝對(duì)象

像Spring IoC容器,PicoContainer以及Guice都無(wú)法圓滿的解決這些問(wèn)題或者說(shuō)它們幾乎做不到!!!

?

Abstractory Factory模式來(lái)實(shí)現(xiàn)DI

?

?

?

現(xiàn)在通過(guò)下面兩種途徑來(lái)改進(jìn)經(jīng)典GoF中的Abstract Factory:

l?????????一個(gè)工廠接口來(lái)代替抽象工廠類(可行)

l?????????每一個(gè)工廠方法的職責(zé)就是創(chuàng)建對(duì)象,并為其注入依賴

?

?

來(lái)看一個(gè)簡(jiǎn)單的例子吧:

?

?

在這里,ComponentA依賴于ComponentB。為方便進(jìn)行單元測(cè)試ComponentAImpl類,接口ComponentB的實(shí)現(xiàn)必須注入到ComponentAImpl中去。下面看看采用Abstract Factory模式完成依賴注入的Java實(shí)現(xiàn)代碼:

?

?//Abstract Factory for Dependency Injection
//Factory interface
public interface Module1ServiceFactory {
?ComponentA getComponentA();
?ComponentB getComponentB();
}

//Concrete factory
public class Module1ServiceFactoryImpl implements Module1ServiceFactory {
?private ComponentA componentA;
?private ComponentB componentB;
?private Module1Servicefactory instance;

?private Module1ServicefactoryImpl() {}

?public static synchronized Module1ServiceFactory getInstance() {
??if (null == instance) {
???instance = new Module1ServicefactoryImpl();
???componentA = new ComponentAImpl();
???componentB = new ComponentBImpl();
???componentA.setComponentB(componentB);
??}
??return instance;
?}

?public ComponentA getComponentA() {
??return componentA;
?}

?public ComponentB getComponentB() {
??return componentB;
?}
}

//Client
public class Client {

?public static void main(String[] args) {
??Module1ServiceFactory m1sf =
???Module1ServicefactoryImpl.getInstance();
??ComponentA componentA = m1sf.getComponentA();
??componentA.operationA1();
?}
}

?

?

?

?

?

延遲加載

?

延遲加載對(duì)象可以通過(guò)改變方法來(lái)實(shí)現(xiàn),比如說(shuō)我現(xiàn)在要稍微對(duì)getComponentA()進(jìn)行改動(dòng),請(qǐng)看:

?

?public synchronized ComponentA getComponentA() {
??if (null == componentA) {
???componentA = new ComponentAImpl();
??}
??return componentA;
?}

?

當(dāng)然我們的Module1ServiceFactoryImpl.getInstance()方法也要進(jìn)行相應(yīng)的改動(dòng)了,我們可以通過(guò)傳遞一個(gè)參數(shù)來(lái)判斷Module1ServiceFactoryImpl.getInstance()是否需要?jiǎng)?chuàng)建對(duì)象。

?

?

?

Singleton作用域

?

上面的代碼僅僅只是建立singleton對(duì)象。如果需要在每次調(diào)用getComponentA()和getComponentB()的時(shí),都返回新創(chuàng)建的對(duì)象的話,我們可以對(duì)我們的Abstract Factory進(jìn)行下面的改動(dòng):

?

//Concrete factory
public class Module1ServiceFactoryImpl {
?private Module1ServiceFactory instance;

?private Module1ServiceFactoryImpl() {}

?public static synchronized Module1ServiceFactory getInstance() {
??if (null == instance) {
???instance = new Module1ServiceFactoryImpl();
??}

return instance;
?}

?public ComponentA getComponentA() {
??ComponentA componentA = new ComponentAImpl();
??ComponentB componentB = getComponentB();
??componentA.setComponentB(componentB);
??return componentA;
?}


?public ComponentB getComponentB() {
??return new ComponentBImpl();
?}
}

?

?

?

?

?

類似的,我們還可以將一個(gè)singleton對(duì)象注入到非singleton對(duì)象中去。比如說(shuō),我們假設(shè)ComponentB此時(shí)是singleton,ComponentA為非singleton,那么我們可以這樣:

?

//Concrete factory
public class Module1ServiceFactoryImpl {
?private Module1ServiceFactory instance;
?private ComponentB componentB;

?private Module1ServicefactoryImpl() {}

?public static synchronized Module1ServiceFactory getInstance() {
??if (null == instance) {
???instance = new Module1ServiceFactoryImpl();
???componentB = new ComponentBImpl();
??}

return instance;
?}

?public ComponentA getComponentA() {
??ComponentA componentA = new ComponentAImpl();
??componentA.setComponentB(componentB);
??return componentA;
?}

?public ComponentB getComponentB() {
??return componentB;
?}
}

?

將一個(gè)非singleton對(duì)象注入到singleton對(duì)象也不是做不到,但這種應(yīng)用場(chǎng)合在現(xiàn)實(shí)世界中是非常罕見(jiàn)的。盡管如此,但在使用dynamic parameters賦級(jí)一個(gè)locallocal變量時(shí),創(chuàng)建一個(gè)非singleton對(duì)象卻很普遍。接下的話題,我們就談?wù)勥@個(gè)。

?

?

?

dynamic parameterssingleton創(chuàng)建一個(gè)local stateful對(duì)象

?

這是所有IoC框架所面臨的問(wèn)題。下面的代碼中,仍然假定ComponentAsingletion

?

?

??public void operationA2() {
??String s = aPrivateMethod();
??int i = anotherMethod();
??ComponentC componentC = new ComponentCImpl(s, i);
??//do something else.
?}

?

?

這里,ComponentAImpl用到了ComponentC接口。雖然,為了更IoC,我們需要將它注入ComponentC的實(shí)現(xiàn),而不是直接硬編碼在ComponentAImpl.operationA2()方法中去,這樣做還有一個(gè)好處就是,方便單元測(cè)試。但問(wèn)題來(lái)了,我們不能將ComponentC作為一個(gè)實(shí)例變量,因?yàn)樗怯袪顟B(tài)的(stateful),它維持著某一個(gè)特定的客戶端狀態(tài),不能與其它客戶端進(jìn)行共享。因此,不能使用常用的setter或construtctor注入方法來(lái)實(shí)現(xiàn)。

?

使用Abstract Factory模式的話,有兩個(gè)方法可以解決這個(gè)問(wèn)題。不過(guò),都得改動(dòng)Module1ServiceFactory接口,添加下面方法:

?

??ComponentC getComponentC(String s, int i);

?

?

請(qǐng)看我在Module1ServiceFactoryImpl中的實(shí)現(xiàn)代碼:

?

public ComponentC getComponentC(String s, int i) {
??return new ComponentCImpl(s, i);
?}
??

?

第一種方法就是將包含它的“工廠”注入到所需的local stateful對(duì)象中去:

?

?private Module1ServiceFactory factory;
?public void setModule1ServiceFactory(Module1ServiceFactory factory) {
??this.factory = factory;
?}

//ComponentAImpl.operationA2() becomes:

?public void operationA2() {
??String s = aPrivateMethod();
??int i = anotherMethod();
??ComponentC componentC = factory.getComponentC(s, i);
??//do something else.
?}

?

?

?

?

缺點(diǎn)顯而易見(jiàn):ComponentAImpl現(xiàn)在與Module1ServiceFactory綁定在一起了,如果要對(duì)ComponentAImpl進(jìn)行單元測(cè)試的話,我們不得不mock一個(gè)Module1ServiceFactory實(shí)現(xiàn)。縱然有這個(gè)缺陷,但直接為stateful對(duì)象注入“工廠”對(duì)象的方法也最為簡(jiǎn)單。類似的技術(shù)廣泛的在J2EE領(lǐng)域采用,比如說(shuō)JPA,將我們將entity manager factory可以注入到應(yīng)用程序代碼后,它就專門負(fù)責(zé)管理自身創(chuàng)建的application-managed entity。(注:如果熟悉Hibernate的話,也可以將entity manager factory想象成HibernateSessionFacory?application-managed entity想象成Session

?

?

第二種方法就是將方法抽出,移到抽象類中去,便于單元測(cè)試:

?

?

?

?public abstract class AbstractComponentA implements ComponentA {
public void operationA2() {
??String s = aPrivateMethod();
??int i = anotherMethod();
??ComponentC componentC = getComponentC(s, i);
??//do something else.
?}

?public abstract ComponentC getComponentC(String s, int i) ;

}

public class ComponentAImpl extends AbstractComponentA {
?public ComponentC getComponentC(String s, int i) {
??return new ComponentCimpl(s, i);
?}

}

?

?

這種方式類似于Springframework的方法注入(Metod Injection),不過(guò)Spring不需要傳遞dynamic parameter也能創(chuàng)建stateful對(duì)象。此時(shí),單元測(cè)試可以不需要再實(shí)現(xiàn)任何mock工廠。但是,這仍然是一個(gè)笨拙的辦法。設(shè)想一下,我們的類里如果有10個(gè)這樣的local stateful對(duì)象,那么我們需要提供10個(gè)抽象方法,才能再次讓單元測(cè)試變得簡(jiǎn)單,可是代價(jià)就造成是更加混亂的應(yīng)用程序代碼。

?

Springframework還可以通過(guò)使用Java反射機(jī)構(gòu)還解決類似問(wèn)題。但這更加復(fù)雜了,并且不適合正常應(yīng)用程序編碼工作。

?

?

處理創(chuàng)建對(duì)象時(shí)拋出的checked exceptions

?

這個(gè)問(wèn)題也是讓IoC容器頭痛的。如果checked exception在對(duì)象創(chuàng)建時(shí)拋出,應(yīng)用程序可能希望是能捕獲并且能夠恢復(fù)。我們來(lái)看一下這個(gè)關(guān)于Web Service的需求實(shí)例:當(dāng)客戶端嘗試建立web servicestub時(shí),并且此時(shí)服務(wù)端web service還不可用,那么客戶端是能夠捕獲stub所拋出的異常,然后顯示相應(yīng)信息,并詢問(wèn)用戶是否稍后繼續(xù)再次連接。如果單純用IoC容器的話,拋出具體指定的checked exception是很困難的。而手工代碼卻可以很輕松的解決這個(gè)問(wèn)題——我們可以簡(jiǎn)單的將“工廠”的checked exceptions拋出,留給應(yīng)用程序代碼去手工處理或者恢復(fù)它們。

?

?

動(dòng)態(tài)封裝對(duì)象

很多場(chǎng)合下,一個(gè)接口對(duì)應(yīng)著多個(gè)不同的實(shí)現(xiàn)類,類型實(shí)例就是設(shè)計(jì)模式中的策略模式。那么,用一個(gè)參數(shù)就可以決定具體哪個(gè)實(shí)現(xiàn)類應(yīng)該被注入到相應(yīng)的封裝對(duì)象中去。然而使用基于XMLIoC容器是靜態(tài)封裝對(duì)象,很難實(shí)現(xiàn)此功能。也許編程式的IoC容器可以解決動(dòng)態(tài)依賴問(wèn)題,但我要說(shuō)的是我們的Abstract Factory則更簡(jiǎn)單直接,看看下面的代碼就知道了:

?

?

?

?

?//Concrete factory
public class Module1ServiceFactoryImpl {
?...

?public ComponentA getComponentA(int strategy) {
??ComponentA componentA = new ComponentAImpl();
??ComponentB componentB = getComponentB(strategy);
??componentA.setComponentB(componentB);
??return componentA;
?}


?public ComponentB getComponentB(int strategy) {
??switch(strategy) {
???case STRATEGYA:
????return new StrategyA();
???case STRATEGYB:
????return new StrategyB();
???default:
????return null;
??????????????????????? }
?}
}

?

?

?

注意這里StrategyA和StrategyB共享實(shí)現(xiàn)了ComponentB接口。

?

?

?

?

結(jié)束語(yǔ)

?

今天我們談到的運(yùn)用依賴注入和Absratct Factory設(shè)計(jì)模式來(lái)解決下列問(wèn)題:

1.???通過(guò)動(dòng)態(tài)參數(shù),創(chuàng)建local stateful對(duì)象

2.???處理創(chuàng)建對(duì)象時(shí)拋出的checked exceptions

3.???動(dòng)態(tài)封裝注入對(duì)象

?

除此以外,該方法與其它IoC容器相比,性能更好,畢竟是直接硬編碼嘛。那么最大的缺點(diǎn)自然就是要手工寫很多基礎(chǔ)代碼了,并且如果要延遲加載與主動(dòng)加載之間來(lái)回切換的話,代碼的改動(dòng)量是很可觀的。不過(guò)呢,這樣的需求幾乎是不存在的。

?

可單元測(cè)試的關(guān)鍵點(diǎn)是基于接口而非實(shí)體類編程。這樣的話mock對(duì)象可以注入到任何需要注入的地方去。

?

不管怎么樣,有時(shí)候在我們的應(yīng)用程序中,依賴注入是一個(gè)不得不解決的問(wèn)題。所有IoC容器以及手工的依賴注入解決方案都是專注于各自的領(lǐng)域——Spring IoC使用XML配置,Google Guice使用特殊的Java,我們的Abstract Factory也是如此。通過(guò)這些解決方案,我們可以避免應(yīng)用程序中到處顯現(xiàn)依賴的編碼,類與類之間耦合度降低,使用Mock對(duì)象就可以正常進(jìn)行單元測(cè)試。

對(duì)所有的IoC容器來(lái)說(shuō),無(wú)論是聲明式的還是編程式的,它們的目的就是作為一個(gè)對(duì)象創(chuàng)建和封裝工廠。同樣我們的Abstract Factory也是如此,只不過(guò)這是一個(gè)可定制的依賴注入解決方案。

最后,使用IoC容器,我們可以消除類與類之間的依賴,從而讓單元測(cè)試變得更加簡(jiǎn)單。但代價(jià)就是你不得不再次依賴于第三方Jar包或XML配置文件。IoC容器并沒(méi)有一個(gè)統(tǒng)一的標(biāo)準(zhǔn),每個(gè)框架所提供的特性和功能都是不同的,因?yàn)橐坏┠闶褂昧四硞€(gè)IoC框架,就意味

總結(jié)

以上是生活随笔為你收集整理的应用抽象工厂模式自己动手写一个ioc的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。