使用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