私はの異なるテキストを分析するパイプラインベースのアプリケーションを持っています(例えば、英語と中国語)私のゴールは、の透明なという形で両方の言語で動作するシステムを持つことです。 注::この質問には、簡単なコードスニペットがたくさんあるため、長いです。パイプラインベースのシステムのアーキテクチャ/設計このコードを改善するには?
コンポーネントが緊密に結合されないように、パイプラインは、三つの成分(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
}
}
現在、パイプラインのすべてのコンポーネントには、言語固有のものがあります。たとえば、中国語のテキストを分析するには、1つのlibが必要であり、英語のテキストを分析するために、別の別のlibが必要です。
さらに、1つの言語で実行できるタスクもあり、もう一方のタスクでは実行できないタスクもあります。この問題に対する1つの解決策は、すべてのパイプラインコンポーネントを抽象的な(いくつかの一般的なメソッドを実装するために)抽象化し、具体的な言語固有の実装を行うことです。また
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 ...
}
、各パイプラインコンポーネントは非常に重く、私はそれらを再利用する必要があるので、私はコンポーネントをキャッシュする工場を作成するので考えた:成分Aを例示する、私は次の必要があるだろうさらに使用するには、(他のコンポーネントは、同じように動作します)のようなので、キーなどの言語を使用してマップを使用して:
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
メソッドからわかるように、まずInputの言語を特定し、それに基づいてパイプラインコンポーネントを特定の言語に変更する必要があります。だから、代わりに直接コンポーネントを呼び出すと、多分私はそうのように、工場からそれらを取得する必要があります。
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);
}
ここまでお読みいただきありがとうございました。私はこの質問にあなたができるすべての提案を非常に感謝します。
コメントと提案をありがとう!ビルダーのパターンに関する記事を読んだことがありますが、それが正しく理解されていれば、言語を指定すると、コンポーネントA、B、Cの言語固有のバージョンを作成するメソッドを持つ 'PipelineBuilder'を作成し、そして、 "ちょうど造られた"言語特有のパイプラインを返す方法。次に、私は 'パイプライン'を受け取り、 'runPipeline'を実行する'パイプラインエンジン 'を持っています。さて、私の問題は、実行時に言語/パイプラインを切り替えることです。毎回新しいパイプラインを作成するのは非常にコストがかかります。どのようにキャッシュできますか? –
拡張と実装の問題については、その記事も読んでいますが、読んだほうがいいですが、コレクションの例が何らかの理由で見逃していると思いますが、問題が発生します。しかし、私の特別なケースでは、すべての言語固有のコンポーネント間で共有する必要のある重いオブジェクトと、それらを操作する一般的なメソッドがあるので、 '' abstract''クラスがあります。 –