4

インターフェイスで表されるフィルターのようなエンティティを設計し、Content オブジェクトに適用できるメソッドをFilter宣言する必要があります。apply(Content content)フィルターは、ワークフローと同様にチェーンで一緒に構成できますが、これらは動的です。たとえば、FilterA が X を返す場合、filterB を適用し、結果 Y を受け取ると FilterC を適用します。フィルターのチェーンはアプリケーション固有であり、フィルター チェーンの構築を許可する方法はまだ決めていません。

filter.apply(content)この動作は、一部のワークフロー フレームワークと同じ方法で設計します。つまり、フィルターのリストを繰り返し処理し、各フィルターを呼び出すマネージャー コンポーネントです。しかし、if/else ステートメントのようなダイナミズムを許可するにはどうすればよいでしょうか?

今のところ、ワークフローまたは FilterChain インターフェースを考え、getNextFilter(previousResult). このインターフェイスを実装すると、アプリケーション固有のワークフローを宣言できます。しかし、Workflow インターフェイスの実装は退屈です: 現在のステップ (整数?) を追跡し、各getNextFilter()呼び出しで、switch/case ステートメントを介して次のフィルターを決定する?!?

どのソリューションがより良いでしょうか? チェーンを宣言するには?

JavaとSpringを使っているのでIoCが使えます。

4

5 に答える 5

3

この場合、チェーンをモデル化し、ノードにもう少し「知性」を与えることで、実行の責任をチェーン自体に移そうとします。ある意味で、ノードはコマンドであると考えます。つまり、ノードは自分自身を実行でき、共通のインターフェースを持つことでコンポジットを作成できるという意味です。(ちなみに、私は Java プログラマーではないので、構文エラーの可能性についてはご容赦ください)。したがって、私の主な設計上の決定は次のとおりです。

  1. チェーンは自分自身を実行する方法を知っています。
  2. チェーン ノードはコンポジットにすることができます。

次のようなものを定義することから始めます。

public abstract class ChainNode {
   public abstract Content apply(Content content);
}

/** 
   The NullObject of the chain 
   http://www.oodesign.com/null-object-pattern.html
*/
public class FinalNode extends ChainNode {
    public Content apply(Content content) {
        return content;
    }
}

/** A sample filter */
public class FilterA extends ChainNode {
    private ChainNode nextNode;

    FilterA(ChainNode nextNode) {
        this.nextNode = nextNode;
    } 

    public Content apply(Content content) {
        filteredValue = //Apply the filter
        return nextNode.apply(filteredValue);
    }
}

/** An if-then-else filter */
public abstract class ConditionalFilter extends ChainNode {
    private ChainNode trueFilter;
    private ChainNode falseFilter;

    ConditionalFilter(ChainNode trueFilter, ChainNode falseFilter) {
        this.trueFilter = trueFilter;
        this.falseFilter = falseFilter;
    } 

    public Content apply(Content content) {
       if (this.evalCondition(content)) {
           return this.trueFilter.apply(content);
       } 
       else {
           return this.falseFilter.apply(content);
       }
    }

    private abstract boolean evalCondition(Content content);
}

このアプローチでは、制御構造をオブジェクトに変換し、実行を要求することで、標準の if-then または switch ステートメントとは異なるロジックを作成することもできます。このベースを使用して、さまざまな分岐演算子を持つチェーンを作成し、さまざまなフィルタリング パスをトリガーできます。

注意すべき点は次のとおりです。

  1. フィルターは type の何かを返すと仮定しましたContent。これにより、実際にはフィルターを次々と連鎖させることができます。それはあなたの要件に当てはまると思いますが、よくわかりません。
  2. 新しいフィルターごとに、新しいクラスを作成してapplyメソッドを定義するだけです。
  3. null オブジェクトは常にチェーンの最後のノードであり、チェーン呼び出しを停止します。
  4. 新しい「分岐ノード」をConditionalFilter定義するには、メソッドをサブクラス化し、再定義する必要がありますevalCondition。Java にクロージャがあるかどうかはわかりませんが (ないと思います)、代わりにconditionインスタンス変数を追加してクロージャでパラメータ化することで、新しい条件ごとにサブクラス化を回避できます。あるいは、Java の世界では、このようなことに対してもっと受け入れられている回避策があるかもしれませんが、私にはわかりません :(.
  5. contentパラメータによって条件分岐が決まると仮定しました。決定を下すためにさらに情報が必要な場合は、applyメソッドにコンテキスト オブジェクトを渡すこともできます。必要に応じて、これは構造化オブジェクトにすることも、柔軟性が必要な場合は単なる辞書にすることもできます。

最後に、チェーンの構造についてですが、チェーンが長く複雑な場合は、ここのビルダーがニーズに合っていると思います。

HTH

于 2013-01-28T14:25:38.267 に答える
2

一般性のために、条件は単一のフィルター間だけでなく、フィルターチェーン間でも決定する必要があると仮定しています。

しばらく考えた結果、ここでは複合パターンが非常にうまく適合するように思えます。

  • Component: あなたのFilterインターフェース
  • Leafs: コンクリート フィルター
  • Composite: 「ワークフローまたは FilterChain インターフェイス」

はまたは のConditionalFilterいずれかです。どちらの場合も、比較と 2 つのオブジェクトで初期化され、単一のフィルターまたはフィルター ワークフローのいずれかに分岐できます。LeafCompositeFilter

于 2013-01-28T23:05:44.493 に答える
1

PHP でフィルター チェーンを実装する複合パターンの例を次に示します。

$filter = new BookFilter\Chain();
$filter->appendFilter(new BookFilter\Isbn('978-5-8459-1597-9'))
       ->appendFilter(new BookFilter\Title('Domain Driven', BookFilter\Title::CONTAINS))
       ->appendFilter(new BookFilter\Publisher('Вильямс', BookFilter\Publisher::EQUALS))
       ->appendFilter(new BookFilter\Price(100, 10.000))
       ->appendFilter(new BookFilter\Ebook(true));
$bookCollection = $bookSeachService->findAllByFilter($filter);

ここから取得: http://crazycode.net/blog/6-architecture/10-structural-patterns

于 2015-10-22T12:44:03.573 に答える
0

フィルターチェーンを順番に実行したいだけなので、おそらくフィルターチェーンを として実装するのが最も簡単でしょうList<Filter>。それらをループして実行するだけです。のようなもの (これは明らかに私が試していない簡単な実装であることに注意してください):

public class FilterChainImpl implements FilterChain {
  private List<Filter> filterChain = new ArrayList<Filter>();

  public addFilter(final Filter f) {
    filterChain.add(f);
  }

  public apply(final Content content) {
    Content prevContent = content;
    for(Filter f : filterChain) {
      prevContent = f.apply(prevContent);
    }
  }
}

次に、これを使用して、好きなフィルター チェーンを一般的に作成できます。多くの異なるフィルター チェーンを作成する場合は、フィルター チェーンを作成するためのファクトリ テクニックを使用できます。

于 2013-01-27T22:46:59.563 に答える
0

ここで必要なのは、パターンChain of Responsibilityです。

これをJavaで何度も実装したので、私の推奨事項は次のとおりです。

  • おそらくどこかに完全なチェーンは必要ありません。各アイテムには後続のアイテムへのリンクがあります
  • チェーン内のメンバーの完全なリストが必要な場合は、おそらく LinkedList を使用できます。
  • 複数のチェーンを持つことができることを覚えておいてください
  • 重要な設計上の問題は、部分的な処理があるかどうかです。一般的にはありません。チェーンの各メンバーが見て、処理できる場合は処理し、そうでない場合は後続を呼び出します。

参加メカニズムはインターフェイスである必要があります。これにより、非常に異なることを行い、メッセージを受信して​​インターフェイスの指示に従って渡すことにのみ同意する専門のエージェントを持つことができます。

段階的にフィルタリングしたい場合は、質問に示されているようにコンテンツを渡すことができ、各参加者はそれを変更できます。私は GitHub にスクレイパーと呼ばれるオープン ソース プロジェクトを持っています。このプロジェクトは、Chain of Responsibility を使用して、スクレイピングされるページのコンテンツを含む部分を抽出する一連のエージェントを実装します。

于 2013-01-27T23:21:26.767 に答える