今さらだけど GoF の Chain of Responsibility パターン。「自分に処理できないタスクは上へ投げる」ってやつ。Reactive な感じでやるとこんな感じかなあと思って書いてみた。
void Main()
{
var document = "有給届";
var kakariCho = CreateManager("係長", document, d => String.Equals(document, "遅刻届"));
var kaCho = CreateManager("課長", document, d => String.Equals(document, "有給届"));
var buCho = CreateManager("部長", document, d => String.Equals(document, "退職届"));
Observable.Concat(new [] {
kakariCho, // 係長
kaCho, // 課長
buCho // 部長
})
.FirstOrDefault() // 最初の1人に承認されたら終了
.Timeout(TimeSpan.FromDays(1)) // 猶予1日
.Subscribe(x => Debug.WriteLine(String.IsNullOrEmpty(x)
? "あなたの届書は却下されました"
: x + "が承認しました"));
}
/// 管理職を作成する(役職名、渡された届書、自分に承認できる届書)
IObservable<string> CreateManager(string managerTitle, string document, Predicate<string> canIAccept)
{
return Observable.Create<string>(o => Task.Run(() =>
{
if (canIAccept(document))
{
o.OnNext(managerTitle); // 承認
}
o.OnCompleted();
}));
}
管理職の人を IObservable
に見立てて、自分が処理できるなら OnNext
を呼ぶ、処理できないなら OnNext
は呼ばずに OnComplete
しちゃう。
で、係長・課長・部長の IObservable を Concat
で役職の低い順につなげて、 FirstOrDefault()
で最初の承認がもらえるまで待つ、みたいな。
係長・課長・部長が誰も承認しなかった時、タイムアウトするまで待ちが発生しちゃうのが難点。→ Take(1)
じゃなくて FirstOrDefault
すればいいみたい。誰も承認しなかった場合 default(string)
つまり空文字が流れてくる。
あと、係長→課長→部長と管理職のハンコリレーが必要な場合に対応できていない、Concat なので係長の結果を課長に引き継いでないから。
んーどうしようか。。。