2

私は、本質的にドキュメントの解析と分析のフレームワークであるアーキテクチャに取り組んでいます。ドキュメントの行が与えられると、フレームワークは最終的にドキュメントを表す大きなオブジェクト ( と呼びますDocument) を生成します。

パイプラインの初期のフィルターは、行単位で動作する必要があります。ただし、さらに下のフィルターでは、Documentオブジェクトを変換 (および最終的に生成) する必要があります。

これを実装するには、次のようなフィルター定義を使用することを考えていました。

public interface IFilter<in TIn, out TOut> {
    TOut Execute(TIn data);
}

すべてのフィルターはPipelineManagerクラスに登録されます (「リンクされたリスト」スタイルのアプローチを使用するのではなく)。実行する前PipelineManagerに、パイプラインの整合性を検証して、フィルターに間違った入力型が与えられていないことを確認します。

私の質問:データ型が変化するパイプラインを使用することは、アーキテクチャ的に適切ですか (つまり、良い考えですか)?

PS アプリケーションをパイプラインとして実装する理由は、プラグインの作成者が既存のフィルターを簡単に置き換えたり拡張したりできると思うからです。変更したいフィルターを別の実装に交換するだけで準備完了です。

4

2 に答える 2

4

編集:注、このwall'o'text grinに置き換えるために他の回答を削除しました

NINJAEDIT: 楽しい事実: Powershell (@Loudenvier の回答で言及) はかつて「モナド」と名付けられる予定でした - また、トピックに関する Wes Dyer のブログ投稿を見つけました: The Marvels of Monads

この「モナド」全体を見る非常に単純な方法の 1 つは、非常に基本的なインターフェースを備えたボックスとして考えることです。

  • 戻る
  • 練る
  • ゼロ (オプション)

使用法も同様に概念的に単純です - 「もの」があるとしましょう:

  • 「物」を箱に入れ(これは「返品」になります)、「BoxOfThing」を持つことができます
  • この箱から物を取り出して別の箱に入れる方法を指示できます(バインド)
  • 空のボックスを取得できます (「ゼロ」: 1 を掛けたり、ゼロを追加したりするような、一種の「操作なし」と考えてください)。
  • (他にもルールはありますが、この3つが一番面白いです)

バインド ビットは非常に興味深い部分であり、ほとんどの人の頭を爆発させる部分でもあります。基本的に、あなたはボックスを連鎖させる方法についてある種の仕様を与えています: "Option" または "Maybe" というかなり単純なモナドを見てみましょう - 少し似てNullable<T>いますが、よりクールです。

したがって、誰もがどこでも null をチェックすることを嫌いますが、参照型が機能する方法のために強制されています。私たちが望んでいるの は、次のようなコードを作成できることです。

var zipcodesNearby = order.Customer.Address.City.ZipCodes;

そして、(顧客が有効である + アドレスが有効である + ...) 場合は有効な回答を返すか、そのロジックのいずれかのビットが失敗した場合は「何もありません」...しかし、いいえ、次のことを行う必要があります。

List<string> zipcodesNearBy = new List<string>();
if(goodOrder.Customer != null)
{
    if(goodOrder.Customer.Address != null)
    {
        if(goodOrder.Customer.Address.City != null)
        {
            if(goodOrder.Customer.Address.City.ZipCodes != null)
            {
                zipcodesNearBy = goodOrder.Customer.Address.City.ZipCodes;
            }
            else { /* do something else? throw? */ }
        }
        else { /* do something else? throw? */ }
    }
    else { /* do something else? throw? */ }
}
else { /* do something else? throw? */ }

(注:該当する場合は、ヌル合体に頼ることもできます-見た目はかなり悪いですが)

List<string> nullCoalescingZips = 
    ((((goodOrder ?? new Order())
        .Customer ?? new Person())
            .Address ?? new Address())
                .City ?? new City())
                    .ZipCodes ?? new List<string>();

Maybe モナドの「ルール」は次のようになります。

(注: C# はこのタイプの型マングリングには理想的ではないため、少し不安定になります)

public static Maybe<T> Return(T value)
{
    return ReferenceEquals(value, null) ? Maybe<T>.Nothing : new Maybe<T>() { Value = value };
}
public static Maybe<U> Bind<U>(Maybe<T> me, Func<T, Maybe<U>> map)
{
    return me != Maybe<T>.Nothing ?
        // extract, map, and rebox
        map(me.Value) :
        // We have nothing, so we pass along nothing...
        Maybe<U>.Nothing;
}

しかし、これはいくつかのNASTYコードにつながります:

var result1 = 
    Maybe<string>.Bind(Maybe<string>.Return("hello"), hello =>
        Maybe<string>.Bind(Maybe<string>.Return((string)null), doh =>
            Maybe<string>.Bind(Maybe<string>.Return("world"), world =>
                hello + doh + world).Value
            ).Value
        );

幸いなことに、きちんとしたショートカットがあります:SelectManyこれは "Bind" とほぼ同等です:

SelectMany私たちのために実装するとMaybe<T>...

public class Maybe<T>
{
    public static readonly Maybe<T> Nothing = new Maybe<T>();
    private Maybe() {}
    public T Value { get; private set;}
    public Maybe(T value) { Value = value; }
}
public static class MaybeExt
{
    public static bool IsNothing<T>(this Maybe<T> me)
    {
        return me == Maybe<T>.Nothing;
    }
    public static Maybe<T> May<T>(this T value)
    {
        return ReferenceEquals(value, null) ? Maybe<T>.Nothing : new Maybe<T>(value);
    }
    // Note: this is basically just "Bind"
    public static Maybe<U> SelectMany<T,U>(this Maybe<T> me, Func<T, Maybe<U>> map)
    {
        return me != Maybe<T>.Nothing ?
            // extract, map, and rebox
            map(me.Value) :
            // We have nothing, so we pass along nothing...
            Maybe<U>.Nothing;
    }
    // This overload is the one that "turns on" query comprehension syntax...
    public static Maybe<V> SelectMany<T,U,V>(this Maybe<T> me, Func<T, Maybe<U>> map, Func<T,U,V> selector)
    {
        return me.SelectMany(x => map(x).SelectMany(y => selector(x,y).May()));
    }
}

これで、LINQ 内包構文に便乗できるようになりました。

var result1 = 
    from hello in "Hello".May()
    from oops in ((string)null).May()
    from world in "world".May()
    select hello + oops + world;
// prints "Was Nothing!"
Console.WriteLine(result1.IsNothing() ? "Was Nothing!" : result1.Value);

var result2 = 
    from hello in "Hello".May()
    from space in " ".May()
    from world in "world".May()
    select hello + space + world;
// prints "Hello world"
Console.WriteLine(result2.IsNothing() ? "Was Nothing!" : result2.Value);

var goodOrder = new Order { Customer = new Person { Address = new Address { City = new City { ZipCodes = new List<string>{"90210"}}}}};
var badOrder = new Order { Customer = new Person { Address = null }};

var zipcodesNearby = 
    from ord in goodOrder.May()
    from cust in ord.Customer.May()     
    from add in cust.Address.May()
    from city in add.City.May()
    from zip in city.ZipCodes.May()
    select zip;
// prints "90210"
Console.WriteLine(zipcodesNearby.IsNothing() ? "Nothing!" : zipcodesNearby.Value.FirstOrDefault());

var badZipcodesNearby = 
    from ord in badOrder.May()
    from cust in ord.Customer.May()     
    from add in cust.Address.May()
    from city in add.City.May()
    from zip in city.ZipCodes.May()
    select zip;
// prints "Nothing!"
Console.WriteLine(badZipcodesNearby.IsNothing() ? "Nothing!" : badZipcodesNearby.Value.FirstOrDefault());

はは、これの要点全体を言及するのを忘れていたことに気付きました...つまり、基本的に、パイプラインの各段階で「バインド」に相当するものが何であるかを理解したら、同じタイプのシュードモナディック コードを使用して各型変換のラッピング、アンラッピング、および処理を処理します。

于 2012-12-07T22:09:18.993 に答える
2

これはあなたの質問に答えることはできませんが、.NETの世界でパイプラインのインスピレーションを探すのに最適な場所はPowerShellです。彼らは非常に巧妙な方法でパイプラインモデルを実装しており、パイプラインを流れるオブジェクトは常に変化します。

過去にデータベースからPDFへのドキュメント作成パイプラインを作成する必要があり、PowerShellコマンドレットとして作成しました。非常に拡張性があったため、数年後も引き続き積極的に使用および開発されており、PowerShell 1から2に移行しただけで、現在は3に移行している可能性があります。

ここで素晴らしいアイデアを得ることができます:http://blogs.technet.com/b/heyscriptingguy/

于 2012-12-07T20:35:12.937 に答える