2016-04-06 4 views
5

私は、専門業務と訪問者パターンを持つ複数の葉ノードクラスを持つ複合パターンを使用しています。この例では、分かりやすくするためにすべての明白なacceptメソッドを除外しました。訪問者パターンとコンポジットパターンを使用してフィルタリングされたストリームを構築する

interface Command { 
    public int getCost(); 
} 

class SimpleCommand implements Command { 
    private int cost; 

    public int getCost() { 
     return cost; 
    } 
} 

class MultiCommand implements Command { 
    private Command subcommand; 
    private int repeated; 

    public int getCost() { 
     return repeated * subcommand.getCost(); 
    } 

    public void decrement() { 
     if (repeated > 0) 
      repeated--; 
    } 
} 

class CommandList implements Command { 
    private List<Command> commands; 

    public int getCost() { 
     return commands.stream().mapToInt(Command::getCost).sum(); 
    } 

    public void add(Command command) { 
     commands.add(command); 
    } 
} 

interface CommandVisitor { 
    default void visitSimpleCommand(SimpleCommandCommand command) { } 
    default void visitMultiCommand(MultiCommand multiCommand) { } 
    default void visitCommandList(CommandList commandList) { } 
} 

訪問者を作成してdecrementなどの操作を実行できるようになりました。

class MultiCommandCollector implements CommandVisitor { 
    private final Stream.Builder<MultiCommand> streamBuilder = Stream.builder(); 

    public static Stream<MultiCommand> streamFor(Command command) { 
     MultiCommandVisitor visitor = new MultiCommandVisitor(); 
     command.accept(visitor); 
     return visitor.streamBuilder.build(); 
    } 

    public void visitMultiCommand(MultiCommand multiCommand) { 
     builder.accept(multiCommand); 
    } 
} 

これは、あなたが期待するとして使用されます。しかし、私はそれが簡単に任意の操作がそれらに対して実行できるように、特定のクラスのオブジェクトをストリーム汎用訪問者を作成するために見つけます。たとえば、

MultiCommandCollector.streamFor(command).forEach(MultiCommand::decrement); 

これには1つの重要な制限があります。これは、ストリームが処理されるときに階層を変更するために使用できません。たとえば、次のように失敗した:

CommandListCollector.streamFor(commandList).forEach(cl -> cl.add(command)); 

私はこれを可能にする代替エレガントなデザインを考えることはできません。

私の質問は、階層を変更できる汎用ビジターを許可するためにこのデザインが自然に拡張されていますか?言い換えれば、ビジターが1人のメンバーにアクセスして階層を更新してから次のメンバーにアクセスできる方法はありますか?これはストリームの使用に対応していますか?

答えて

0

私の以前の経験では、Visitorパターンは階層をクエリしたり再作成するのに便利です。クエリ部分は明白です。特定のタイプのサブオブジェクトをリッスンして、適合しているクエリ結果を構築するだけです。もう一つの質問は、階層を変えることです。

階層の反復処理中に階層を変更することが実際に困難になることがあります。したがって、私は実際にうまく動作する2つの便利なテクニックを知っています。

  1. 階層にアクセスしながら、変更するオブジェクトのリストを作成します。 訪問が完了するまで変更しないでください。具体的な訪問者 は、プライベートなメンバーとして関心のあるオブジェクトのリストを構築できます。 が訪問を完了すると、結果としてオブジェクトのリストが公開されます。 その後、結果のリストを反復処理し、オブジェクトを に変更します。
  2. 階層にアクセスしているときに、要素を訪問するときに、要素 のコピーを作成します。要素を変更する必要がある場合は、変更した バージョンを作成します。そうでない場合、要素を変更する必要がない場合は、新しい要素の として返します。すべての訪問が完了したら、新しい階層 が作成され、すべての変更が意図した通りに行われます。古い階層は 逆参照され、ガベージコレクタは が新しいものに置き換えられた要素を収集します。

最初のアルゴリズムは、要素が変更可能な場合に適用できます。 2番目のアルゴリズムは、要素が不変の場合に適用できます。

これが役に立ちます。

関連する問題