既存のWebサービスの特定の側面のリファクタリングに取り組んでいます。サービスAPIの実装方法は、一連のタスクが順番に実行される「処理パイプライン」のようなものを持つことです。当然のことながら、後のタスクは前のタスクによって計算された情報を必要とする場合があり、現在これを行う方法は「パイプライン状態」クラスにフィールドを追加することです。
私は、無数のフィールドを持つデータオブジェクトを持つよりもパイプラインステップ間で情報を共有するより良い方法があると考えています(そして望んでいますか?)このクラスをスレッドセーフにするのは大きな苦痛になります(可能かどうかはわかりません)、その不変式について推論する方法はありません(そしておそらくないかもしれません)。
私はインスピレーションを見つけるためにGang of Fourのデザインパターンブックをページングしていましたが、そこに解決策があるとは感じませんでした(Mementoはやや同じ精神ですが、まったく同じではありませんでした)。私もオンラインで調べましたが、「パイプライン」または「ワークフロー」を検索する2番目のケースでは、Unixパイプ情報、または独自のワークフローエンジンとフレームワークのいずれかであふれています。
私の質問は、ソフトウェア処理パイプラインの実行状態を記録する問題にどのようにアプローチし、後のタスクが以前のタスクによって計算された情報を使用できるようにするかです。Unixパイプとの主な違いは、直前のタスクの出力だけを気にしないことです。
要求されたとおり、私のユースケースを説明するためのいくつかの擬似コード:
「パイプラインコンテキスト」オブジェクトには、さまざまなパイプラインステップで入力/読み取りできるフィールドがあります。
public class PipelineCtx {
... // fields
public Foo getFoo() { return this.foo; }
public void setFoo(Foo aFoo) { this.foo = aFoo; }
public Bar getBar() { return this.bar; }
public void setBar(Bar aBar) { this.bar = aBar; }
... // more methods
}
パイプラインの各ステップもオブジェクトです。
public abstract class PipelineStep {
public abstract PipelineCtx doWork(PipelineCtx ctx);
}
public class BarStep extends PipelineStep {
@Override
public PipelineCtx doWork(PipelieCtx ctx) {
// do work based on the stuff in ctx
Bar theBar = ...; // compute it
ctx.setBar(theBar);
return ctx;
}
}
同様に、FooStep
他のデータとともに、その前にBarStepによって計算されたBarを必要とするかもしれない仮想的なについても同様です。そして、実際のAPI呼び出しがあります。
public class BlahOperation extends ProprietaryWebServiceApiBase {
public BlahResponse handle(BlahRequest request) {
PipelineCtx ctx = PipelineCtx.from(request);
// some steps happen here
// ...
BarStep barStep = new BarStep();
barStep.doWork(crx);
// some more steps maybe
// ...
FooStep fooStep = new FooStep();
fooStep.doWork(ctx);
// final steps ...
return BlahResponse.from(ctx);
}
}