У меня есть приложение на основе конвейера, которое анализирует текст на различных языках (скажем, английском и китайском). Моя цель - иметь систему, которая может работать на обоих языках, прозрачным способом. ПРИМЕЧАНИЕ : Этот вопрос длинный, поскольку в нем много простых фрагментов кода.
Конвейер состоит из трех компонентов (назовем их A, B и C), и я создал их следующим образом, чтобы компоненты не были тесно связаны:
public class Pipeline {
private A componentA;
private B componentB;
private C componentC;
// I really just need the language attribute of Locale,
// but I use it because it's useful to load language specific ResourceBundles.
public Pipeline(Locale locale) {
componentA = new A();
componentB = new B();
componentC = new C();
}
public Output runPipeline(Input) {
Language lang = LanguageIdentifier.identify(Input);
//
ResultOfA resultA = componentA.doSomething(Input);
ResultOfB resultB = componentB.doSomethingElse(resultA); // uses result of A
return componentC.doFinal(resultA, resultB); // uses result of A and B
}
}
Теперь у каждого компонента конвейера есть что-то, что зависит от языка. Например, для анализа китайского текста мне нужна одна библиотека, а для анализа английского - другая.
Кроме того, есть некоторые задачи, которые могут быть выполнены на одном языке, и не могут быть выполнены на другом. Одним из решений этой проблемы является сделать каждый компонент конвейера абстрактным (для реализации некоторых распространенных методов), а затем иметь конкретную конкретную языковую реализацию. В качестве примера с компонентом A я бы получил следующее:
public abstract class A {
private CommonClass x; // common to all languages
private AnotherCommonClass y; // common to all languages
abstract SomeTemporaryResult getTemp(input); // language specific
abstract AnotherTemporaryResult getAnotherTemp(input); // language specific
public ResultOfA doSomething(input) {
// template method
SomeTemporaryResult t = getTemp(input); // language specific
AnotherTemporaryResult tt = getAnotherTemp(input); // language specific
return ResultOfA(t, tt, x.get(), y.get());
}
}
public class EnglishA extends A {
private EnglishSpecificClass something;
// implementation of the abstract methods ...
}
Кроме того, поскольку каждый компонент конвейера очень тяжелый, и мне нужно их повторно использовать, я подумал о создании фабрики , которая кэширует компонент для дальнейшего использования, используя карту, использующую язык в качестве клавиша, как это (другие компоненты будут работать так же):
public Enum AFactory {
SINGLETON;
private Map<String, A> cache; // this map will only have one or two keys, is there anything more efficient that I can use, instead of HashMap ?
public A getA(Locale locale) {
// lookup by locale.language, and insert if it doesn't exist, et cetera
return cache.get(locale.getLanguage());
}
}
Итак, мой вопрос : Что вы думаете об этом дизайне? Как это может быть улучшено ? Мне нужна «прозрачность», потому что язык может быть изменен динамически, основываясь на тексте, который он анализирует. Как видно из метода runPipeline
, я сначала идентифицирую язык ввода, а затем, основываясь на этом, мне нужно изменить компоненты конвейера на идентифицированный язык. Таким образом, вместо того, чтобы вызывать компоненты напрямую, возможно, я должен получить их с завода, вот так:
public Output runPipeline(Input) {
Language lang = LanguageIdentifier.identify(Input);
ResultOfA resultA = AFactory.getA(lang).doSomething(Input);
ResultOfB resultB = BFactory.getB(lang).doSomethingElse(resultA);
return CFactory.getC(lang).doFinal(resultA, resultB);
}
Спасибо, что прочитали это далеко. Я очень ценю каждое предложение, которое вы можете сделать по этому вопросу.