5

同じトラバーサルコードを何度も書き直すことなく、各ノードでX量のインラインアクションを
実行して、バイナリツリークラスを取得してそのノードをトラバースできる方法を見つけようとしています。 Javaが関数ポインタを許可していれば、これは私が理解するのがはるかに簡単になると思います...


基本的に、私が必要とするのは次のようなものです。

public class BinaryTreeNode {

    //...

    public void inOrderTraversalFrom(BinaryTreeNode node, /* ??? */ actions) {
        if(node.left != null)
            inOrderTraversalFrom(node.left);

        /* do something with "actions" here */

        if(node.right != null)
            inOrderTraversalFrom(node.right);
    }
}


...アクションにより、各ノードで実行されるアクションのタイプに応じて異なるパラメーターのセットを取り込んで、さまざまなメソッドを実行できる場合があります。

この良い例は、これらのノードを描画することを目的としたクラスを渡すことができ、そのパラメータの1つとしてGraphicsオブジェクトを受け入れることです。これに対して、Graphicsを必要としない他の一連のアクションを実行することを目的としたクラスです。パラメータとしてのオブジェクトですが、代わりに完全に異なるパラメータのセットです。

これはどのように可能ですか?これを実行するための最も動的な方法は何でしょうか?

4

3 に答える 3

1

それを行う1つの方法は次のとおりです。

actionを受け取り、Nodeそれにアクションを適用するクラスのインスタンスである可能性があります。

public interface Action{
  public void apply(Node node){
  // To be done in the classes that will implement 
  // this interface. If it's a graphic-display of the nodes, the apply 
  // method will call draw(node.value), for example
  }
}

この線:

/* do something with "actions" here */

に置き換える必要があります

action.apply(node);

メソッドのシグネチャを次のように変更する必要があります。

public void inOrderTraversalFrom(BinaryTreeNode node, Action action)

再帰呼び出しは次のようになります。

inOrderTraversalFrom(node.left, action);
于 2013-03-09T04:18:12.140 に答える
1

私は解決策を見つけましたが、それは最善ではないかもしれません...

BinaryTreeNode.java:

public void inOrderTraversalFrom(BinaryTreeNode rootNode, BinaryTreeActions actions)
{
    if(rootNode.left != null)
        inOrderTraversalFrom(rootNode.left, actions);

    if(actions != null)
        actions.Perform(rootNode);

    if(rootNode.right != null)
        inOrderTraversalFrom(rootNode.right, actions);
}


BinaryTreeActions.java:

public interface BinaryTreeActions {
    public void Perform(BinaryTreeNode node);
}


BinaryTreeGraphicsActions.java:

public interface BinaryTreeGraphicsActions extends BinaryTreeActions {
    void DrawNode(BinaryTreeNode node, Graphics g);
}


BinaryTreeView.java:

private void DrawNodes(final Graphics graphics)
{
    BinaryTreeNode node = root;
    root.inOrderTraversalFrom(node, new BinaryTreeGraphicsActions() {
        @Override
        public void DrawNode(BinaryTreeNode node, Graphics g) {
            // draw the node
        }

        @Override
        public void Perform(BinaryTreeNode node) {
            DrawNode(node, graphics);
        }
    });
}


...そして、新しいアクションのセットが必要なときはいつでも、との同じアイデアに従って、そのための新しいインターフェイスを作成しBinaryTreeGraphicsActionsますBinaryTreeView。これにより、設計したインターフェースに応じて、任意のアクションのセットを実行できます。


#EDIT:BinaryTreeActionsBinaryTreeGraphicsActionsを使用するだけで同じインラインコードを実行できる ため、の必要がないことを発見した後、同様の回答を受け入れました。

private void DrawNodes(final Graphics graphics)
{
    BinaryTreeNode node = root;
    root.inOrderTraversalFrom(node, new BinaryTreeActions() {
        @Override
        public void Perform(BinaryTreeNode node) {
            /* draw the node, using any local vars (providing they are final) */
        }
    });
}
于 2013-03-09T04:46:20.160 に答える
0

次の解決策は、ここで提案されている他の解決策と非常によく似ています。しかし、これらのことに興味がある場合は、いくつかのデザインパターンのアイシングがあります。

アイデアは、アクションだけでなくトラバーサルも分離することです。これは、次の2つの抽象化で実行できます。

  • BinaryTreeNodeTraversalStrategy
  • BinaryTreeNodeVisitor


public interface Visitable<T extends Visitor> {

  public void accept(T visitor);
}

public interface Visitor<T extends Visitable> {

  public void visit(T visitable);
}

public interface BinaryTreeNode implements Visitable<BinaryTreeNodeVisitor> {

  public void accept(BinaryTreeNodeVisitor visitor);
}

public interface BinaryTreeNodeVisitor implements Visitor<BinaryTreeNode> {

  public void visit(BinaryTreeNode visitable);
}

public interface BinaryTreeNodeTraversalStrategy {

  public void traverse(BinaryTreeNode root);
}
于 2013-03-09T05:02:55.250 に答える