4

承認プロセスをモデル化する必要があります。以前はかなり単純でした。2 つのロールが何かを承認する必要があり、その後、次のステップに進むことができました。

public class Approved
{
    public string ApproverRole;
}

var approvals = Subscribe<Approved>();

var vpOfFinance = approvals.Where(e => e.ApproverRole == "Finance VP");
var vpOfSales = approvals.Where(e => e.ApproverRole == "Sales VP");

var approvedByAll = vpOfFinance.Zip(vpOfSales, Tuple.Create);

approvedByAll.Subscribe(_ => SomeInterestingBusinessProcess());

ただし、新しい要件があります。何かを承認するために必要な役割の数はさまざまです。

public class ApprovalRequested
{
    public string[] Roles;
}
var approvalRequest = Subscribe<ApprovalRequested>().Take(1);
var approvals = Subscribe<Approved>();

var approvedByAll = ???;

approvedByAll.Subscribe(_ => SomeInterestingBusinessProcess());

ここでかなり明白な何かが欠けているように感じます...誰かが私を正しい方向に向けることができますか?

編集

明確にするために: 承認プロセスは項目ごとに行われます。承認が到着する順序は定義されていません。1 つのロールが項目を複数回承認してもかまいません。

4

2 に答える 2

2

現在のバージョンの Rx (NuGet から取得) にはZip()、オブザーバブルのコレクションを受け取り、コレクションのオブザーバブルを返すバージョンがあります。これで、次のようなことができます。

string[] requiredApprovals = …;

var approvedByAll = requiredApprovals
    .Select(required => approvals.Where(a => a.ApproverRole == required))
    .Zip();

approvedByAll.Subscribe(_ => SomeInterestingBusinessProcess());

しかし、@Enigmativity が指摘したように、これは、各人が同じ順序で承認し、すべてのアイテムが最終的にすべての必要な役割によって承認されることを確認できる場合にのみ機能します。そうでない場合は、単なる よりも複雑なものが必要になりますZip()

于 2012-09-22T08:32:37.787 に答える
2

この問題は本質的にSet、値の順序が乱れたり、本質的に多数の値のストリームから を作成したりすることに減らすことができます。

N がセットのカーディナリティである場合、少なくとも N 種類の値 (この場合はロール) がプッシュされるまで、プロセスは進まないと自明に推測できます。

Zip 演算子のサンプル ソリューションを次に示します。おそらくこれで始めることができます:

    public static IObservable<IList<T>> Zip<T>(this IList<IObservable<T>> observables)
    {
        return Observable.Create<IList<T>>(observer =>
        {
            List<List<T>> store = new List<List<T>>(Enumerable.Range(1, observables.Count).Select(_ => new List<T>()));

            return new CompositeDisposable(observables.Select((o, i) => 
                o.Subscribe(value =>
                {
                    lock (store)
                    {
                        store[i].Add(value);

                        if (store.All(list => list.Count > 0))
                        {
                            observer.OnNext(store.Select(list => list[0]).ToList());
                            store.ForEach(list => list.RemoveAt(0));
                        }
                    }
                }))
            );
        });
    }

テスト:

        Observable.Interval(TimeSpan.FromSeconds(0.5))
                  .GroupBy(i => i % 3)
                  .Select(gr => gr.AsObservable())
                  .Buffer(3)                      
                  .SelectMany(set => set.Zip())
                  .Subscribe(v => Console.WriteLine(String.Join(",", v)));

ここでの問題の 1 つは、グループが形成されている間に初期値を失う可能性があることです。そのため、メソッドをIObservable<IList<T>> Zip<TKey, T>(this IGroupedObservable<TKey, T> observables).

于 2012-09-22T18:16:37.457 に答える