使用dependency injection。
Spring Framework是一個非常有用的軟件和我個人最喜歡的一塊,但有很多替代品,如Google Guice。
使用Spring,您可以定義兩個(三個,十五個......)單獨的上下文,每個語言一個,並從適當的上下文中獲取所需的組件。它類似於你的第二種方法,但不使用Language
類。例如:
# English context: english.xml
<bean id="Tokenizer" class="EnglishTokenizer"/>
<bean id="Parser" class="EnglishParser"/>
...
# Your code
ApplicationContext englishContext = ...; // context itself is injected
Parser englishParser = (Parser) englishContext.getBean("Parser");
另一種選擇是有一個上下文,但在你的bean id前加上你的語言,例如,「English-Tokenizer」和「Chinese-Tokenizer」。
如果你之前從未使用過依賴注入,這可能聽起來像工作太多,可以通過工廠和/或動態類加載實現: - 但事實並非如此 - 它可以做得更多(你可以配置你的組件的屬性/依賴關係;你不必擔心緩存或維護你自己的單例等),一旦你開始使用它,你會想知道你是如何沒有它的: - )
更新(在第2條評論中回答問題)。
下面是一個示例「ComponentLocator」模式。 ComponentLocator
是一個對Spring沒有依賴性的單例。它的實例(和實現)由上下文注入。
public abstract class ComponentLocator {
protected static ComponentLocator myInstance;
protected abstract <T> T locateComponent(Class<T> componentClass, String language);
public static <T> T getComponent(Class<T> componentClass, String language) {
return myInstance.locateComponent(componentClass, language);
}
}
的ComponentLocator
實現假定在上下文豆類作爲他們的接口名稱,然後分號和語言(例如「com.mypackage.Parser:英文」)命名。 ComponentLocatorImpl必須在上下文中聲明爲bean(bean名稱無關緊要)。
public class ComponentLocatorImpl extends ComponentLocator
implements ApplicationContextAware {
private ApplicationContext myApplicationContext;
public void setApplicationContext(ApplicationContext context) {
myApplicationContext = context;
myInstance = this;
}
@Override
protected <T> T locateComponent(Class<T> componentClass, String language) {
String beanName = componentClass.getName() + ":" + language;
return componentClass.cast(myApplicationContext.getBean(beanName, componentClass));
}
}
在其他地方你的代碼(在main()?)你要加載ApplicationContext
:
ApplicationContext ctx = new ClasspathXmlApplicationContext("components.xml");
注意,你實際上並不需要參考的背景下,直接在其他任何地方應用程序。無論你需要得到你的組件,你只是做:
Parser englishParser = ComponentLocator.getComponent(Parser.class, "English");
Parser chineseParser = ComponentLocator.getComponent(Parser.class, "Chinese");
注意的是,以上僅僅是一種可能的方法,它假設你幾乎只能把你的依賴於語言類的上下文。在你的情況下,這可能是最好的(由於需要同時提供所有語言),否則你會複製所有類(每種語言一次),所以你的A/B/C問題可能不適用於此。
但是,如果你有A/B/C依賴你所能做的就是(我假設A,B,C的接口和的AIMP1,Bimpl,Cimpl是它們的實現):
<bean id="A" class="Aimpl">
<property name="B" ref="B"/>
</bean>
<bean id="B" class="Bimpl">
<property name="C" ref="C"/>
</bean>
<bean id="C" class="Cimpl">
<property name="tokenizer" ref="Tokenizer:English"/>
</bean>
你的實現需要有setB(),setC()和setTokenizer()方法。這比構造函數注入更容易,儘管後者也是可能的。
謝謝,我已閱讀了一些關於DI概念的文章,但我還沒有使用它。但是,我對此有一些疑問:i)我想這些bean可以配置爲將參數傳遞給類的對象,對嗎? ii)我的「應用程序上下文」(系統使用的語言)可以在運行時更改,並且我想知道是否可以使用DI進行更改; iii)通過緩存,你的意思是說,如果我兩次調用englishContext.getBean(「Parser」),第二個將總是返回一個緩存版本? iv)是否可以使用Spring的IoC容器而不是整個框架? – 2009-08-02 00:00:39