5

複合デザインパターンで作成された式があります:

interface TreeExpression{
    void accept(Visitor visitor);
}

abstract class Operator{
    TreeExpression childA;
    TreeExpression childB;

    Operator(TreeExpression a, TreeExpression b){
        this.childA = a;
        this.childB = b;
    }
}

class PlusTreeExpression extends Operator implements TreeExpression{
    public PlusTreeExpression(TreeExpression a, TreeExpression b) {
        super(a, b);
    }

    public void accept(Visitor visitor) {
        this.childA.accept(visitor);
        visitor.visit(this);
        this.childB.accept(visitor);
    }
}

class MultiplyTreeExpression extends Operator implements TreeExpression{
    public MultiplyTreeExpression(TreeExpression a, TreeExpression b) {
        super(a, b);
    }

    public void accept(Visitor visitor) {
        this.childA.accept(visitor);
        visitor.visit(this);
        this.childB.accept(visitor);
    }
}

class IntegerNode implements TreeExpression{
    Integer value;

    IntegerNode(int v){
        this.value = v;
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

式から文字列を取得するためのビジター:

interface Visitor{
    void visit(PlusTreeExpression tree);
    void visit(MultiplyTreeExpression tree);
    void visit(IntegerNode node);
}

class PrintVisitor implements Visitor{
public StringBuffer result = new StringBuffer();


    public void visit(IntegerNode node) {
        result.append(node.value);
    }

    public void visit(PlusTreeExpression tree) {
        result.append("+");
    }

    public void visit(MultiplyTreeExpression tree) {
        result.append("*");
    }

このビジターは機能し、評価式のビジターを作成しようとしていますが、ここで問題があります。私はそれを行う方法をいくつか試しましたが、既存のコードを変更せずに子ツリーからルートに値を取得する方法がわかりません。

4

2 に答える 2

9

私が見る限り、ここでの問題は、ビジターではなくツリー自体でツリーをトラバースする方法を定義していることです。これは有効なアプローチになる可能性がありますが (設計パターンにはバリエーションがあります)、この場合は、ツリー構造をトラバース順序 (前順、順順、後順) から分離する方がよいと思います。実際のところ、このパターンを教える際の典型的な演習は、それぞれが異なるトラバーサルを実行する 3 つのビジターを作成することです。

あなたの場合、私は:

  1. あなたがしたのと同じように式をツリーとして表現しますが、トラバース部分を受け入れるフォームを削除します。コードでは、受け入れは次のようになります。

    public void accept(Visitor visitor)
    {
        visitor.visit(this);
    }
    
  2. ノードの子に public getter を定義して、訪問者がアクセスできるようにします ( getChildA()getChildB()およびgetValue())。

  3. 必要なトラバーサルのタイプのビジターを作成します。式を評価するには、通常、ポストオーダーを使用しますが、式を印刷するには、順序どおりに使用できます(例のように)。したがって、式を評価するために、次のようなもので終了します。

    class EvalVisitor implements Visitor{
    
            public Integer visit(IntegerNode node) {
                return node.getValue();
            }
    
            public Integer visit(PlusTreeExpression tree) {
                return this.visit(tree.getChildA()) + this.visit(tree.getChildB());
            }
    
            public Integer visit(MultiplyTreeExpression tree) {
                return this.visit(tree.getChildA()) * this.visit(tree.getChildB());
            }
        }
    

HTH

于 2013-01-24T12:37:24.187 に答える
0

カップルのヒント:

  1. あなたの質問に対して:「スタック」と呼ばれるデータ構造を考えて(Javaではjava.util.LinkedList便利です)、「逆ポーランド記法」と呼ばれるものを調べてください。

  2. ちなみに、アプローチを単純化することもできます。このコードが何度も繰り返されていることに注意してください。

    public void accept(Visitor visitor) {
        this.childA.accept(visitor);
        visitor.visit(this);
        this.childB.accept(visitor);
    }
    

これは、ケースを追加するほど悪化するだけです。BinaryExpressionそのコードの一部またはすべてを含む (say) という抽象クラスの作成を検討することをお勧めします。

クラスの名前と「accept()」関数ではなく、ある種の整数トークンを使用して特定の操作を識別することを検討することもできますvisit(BinaryExpression)

于 2013-01-23T00:38:59.350 に答える