Использовать внедрение зависимости .
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");
Другая альтернатива - иметь один контекст, но с префиксом идентификаторов вашего бина с вашим языком, например, "English-Tokenizer" и "Chinese-Tokenizer".
Если вы никогда ранее не использовали внедрение зависимостей, это может показаться слишком большой работой для результата, который может быть достигнут с помощью заводской и / или динамической загрузки классов :-) Но это не так - и он может сделать намного больше ( вы можете настроить свойства / зависимости ваших компонентов, вам не нужно беспокоиться о кэшировании или поддержании собственных синглетонов и т. д.), что, как только вы начнете использовать его, вы удивитесь, как вы когда-либо жили без него: )
Обновление (отвечает на вопросы во втором комментарии).
Вот пример шаблона "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
предполагает, что bean-компоненты в вашем контексте названы как имена их интерфейсов, за которыми следуют точка с запятой и язык (например, «com.mypackage.Parser: English»). 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 - это интерфейсы, а Aimpl, 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 (). Это проще, чем внедрение в конструктор, хотя последнее также возможно.