2

仕様パターンの例をいくつか読みましたが、このパターンで実装する方法を理解するのは困難です。

私はクライアントのために巨大なプログラムを開発しています。特定の銀行から XML ファイルをインポートし、各ファイルで検証を行う必要があります。元帳コードにはさまざまな方法があります (subs、bo、rcc)。そのため、ファイルが SUBS を読み取るときは、SUBS メソッドに送信する必要があります。

例:

インターフェース:

  • ブラックバンク
  • ブルーバンク
  • レッドバンク

元帳コード:

  • サブ
  • ボー
  • RCC

結果:

  • BlackBankにはSUBS、BO、RCCがあります
  • BlueBankにはSUBSがあります
  • RedBankにはBOとRCCがあります

サンプルコードを教えてください。または、正しい方向に向けてください。

4

1 に答える 1

10

文脈がないと答えるのは難しいので、私が持っている情報に基づいて何かを作ってみます。

このような単純な仕様インターフェースを作成します

interface ISpecification<T>
{
    IsSatisfiedBy(T obj);
}

次のような「銀行」の基本インターフェースがあるふりをします

interface IBank
{
    LedgerCode LedgerCode { get; set; }
}

LedgerCodes の列挙型

[Flags]
enum LedgerCodes
{
    SUBS, BO, RCC
} 

IBank の LedgerCodes をチェックするための単純なレジャー コード仕様を作成できます (これは非常に一般的であり、ニーズに合わせて特定する必要があります)。

class LedgerCodeSpec : ISpecification<IBank>
{
    private LedgerCode code;

    public LedgerCodeSpecification(LedgerCode code)
    {
        this.code = code
    }

    public override bool IsSatisfiedBy(IBank obj)
    {
        return obj.LedgerCode == code;
    }
}

必要に応じて仕様を使用できます。ここでは、簡単な検証を提供するために使用します。もう 1 つの用途は、リポジトリからデータを取得するなどの「選択」です。

class Bank : IBank
{
    private ISpecification<IBank> spec;
    private LedgerCode code;

    public Bank(ISepcification<IBank> spec)
    {
        this.code = code;
        this.spec = spec;
    }

    public LedgerCode LedgerCode { get; set; }

    public bool IsValid 
    { 
        get
        {
            return spec.IsSatisfiedBy(this);
        }
    } 
}

最後に、上記をすばやくテスト/デモするためのコード

class Main
{
    public static void Main()
    {
        var spec = new LedgerCodeSpec(LedgerCodes.SUB)
        var blueBank = new Bank(spec);

        Console.WriteLine(blueBank.IsValid); // false

        blueBank.LedgerCode = LedgerCodes.RCC | LedgerCodes.SUB;

        Console.WriteLine(blueBank.IsValid); // false

        blueBank.LedgerCode = LedgerCodes.SUB;

        Console.WriteLine(blueBank.IsValid); // true
    }
}

拡張メソッドを追加し、演算子をオーバーライドして、簡潔でより自然に読みやすい仕様を提供する Web 上のいくつかの良い例があります。

class MessageSpecification : Specification<string>
{
    public const int MIN_LENGTH = 5;
    public const int MAX_LENGTH = 60;

    public override bool IsSatisfiedBy(string s)
    {
        Specification<string> length = new LengthSpecification(MIN_LENGTH, MAX_LENGTH);
        Specification<string> isNull = new IsNullSpecification<string>();

        Specification<string> spec = length && !isNull;

        return spec.IsSatisfiedBy(s);
    }
}

私が現在パターンを使用している方法はおそらくやり過ぎですが、ロジックを削除して再利用し、一般的にオブジェクト指向にするというアイデアが好きです。

編集:コメントのいくつかを読んだ後、問題は仕様パターンではなく、一般的なディスパッチの問題に関連しているようです。インターフェイスがあれば、もっと簡単に実行できます。

class BankFacade
{
    public Send(IBlueBank bank)
    {
        // validate with specification
        // do stuff with IBlueBank
    }

    public Send(IRedBank bank)
    {
        // validate with specification
        // do stuff with IRedBank
    }

    //...
}

もう少し考えて、次のようなことができるかもしれません

class Parser
{
    static class RedBankSpecification : ISpecification<XElement>
    {
        public override bool IsSatisfiedBy(XElement element)
        {
            return element.Value.equals("RED");
        }
    }

    public void Parse(XDocument doc)
    {
        var rspec = new RedBankSpecification();

        foreach(XElement e in doc)
        {
            if (r.IsSatisfiedBy(e))
            {
                IRedBank bank = new RedBank(e);
                bankFacade.Send(bank);
            }
        }

        //...
    }
}

ただし、そのパターンは実際には必要ない可能性があり、問題をそれに押し込めようとするべきではありません

于 2013-06-02T14:21:33.213 に答える